From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4E8C4C433FE for ; Fri, 8 Apr 2022 13:05:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236156AbiDHNHj (ORCPT ); Fri, 8 Apr 2022 09:07:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38298 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236080AbiDHNGs (ORCPT ); Fri, 8 Apr 2022 09:06:48 -0400 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 987AA2F3D30; Fri, 8 Apr 2022 06:04:37 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 1C680B82AD2; Fri, 8 Apr 2022 13:04:35 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 095B9C385A1; Fri, 8 Apr 2022 13:04:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1649423073; bh=Dn/JaQ0mW6sRc6wHLKZFmzcVVuUPHxbNR75RWAOXAOA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LUhBzT9+mq422b/Wnz0No24acHLQ0pybhEJhfi0CMZp0wofDXQdvwf9oA5MLvW39f iMYmfAnwRWoQUYLeFNwgF8UwJtMVtFxVJH1egYZiUtneZ6lEafi6u7DImj3Qlk+D7t 9JYHC+51M88MiKPZnIe97T9UZ8lOPysaYr1Zmup8= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org, akpm@linux-foundation.org, torvalds@linux-foundation.org, stable@vger.kernel.org Cc: lwn@lwn.net, jslaby@suse.cz, Greg Kroah-Hartman Subject: Re: Linux 5.16.19 Date: Fri, 8 Apr 2022 15:04:06 +0200 Message-Id: <164942304624388@kroah.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <16494230466218@kroah.com> References: <16494230466218@kroah.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/te= sting/sysfs-fs-f2fs index b268e3e18b4a..91e2b549f817 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -425,6 +425,7 @@ Description: Show status of f2fs superblock in real tim= e. 0x800 SBI_QUOTA_SKIP_FLUSH skip flushing quota in current CP 0x1000 SBI_QUOTA_NEED_REPAIR quota file may be corrupted 0x2000 SBI_IS_RESIZEFS resizefs is in process + 0x4000 SBI_IS_FREEZING freefs is in process =3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 What: /sys/fs/f2fs//ckpt_thread_ioprio diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentatio= n/admin-guide/kernel-parameters.txt index 391b3f9055fe..3e513d69e9de 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3476,8 +3476,7 @@ difficult since unequal pointers can no longer be compared. However, if this command-line option is specified, then all normal pointers will have their true - value printed. Pointers printed via %pK may still be - hashed. This option should only be specified when + value printed. This option should only be specified when debugging the kernel. Please do not use on production kernels. =20 diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/ad= min-guide/sysctl/kernel.rst index 0e486f41185e..d6977875c1b7 100644 --- a/Documentation/admin-guide/sysctl/kernel.rst +++ b/Documentation/admin-guide/sysctl/kernel.rst @@ -795,6 +795,7 @@ bit 1 print system memory info bit 2 print timer info bit 3 print locks info if ``CONFIG_LOCKDEP`` is on bit 4 print ftrace buffer +bit 5 print all printk messages in buffer =3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 So for example to print tasks and memory info on panic, user can:: diff --git a/Documentation/devicetree/bindings/media/i2c/hynix,hi846.yaml b= /Documentation/devicetree/bindings/media/i2c/hynix,hi846.yaml index 85a8877c2f38..1e2df8cf2937 100644 --- a/Documentation/devicetree/bindings/media/i2c/hynix,hi846.yaml +++ b/Documentation/devicetree/bindings/media/i2c/hynix,hi846.yaml @@ -49,7 +49,8 @@ properties: description: Definition of the regulator used for the VDDD power suppl= y. =20 port: - $ref: /schemas/graph.yaml#/properties/port + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false =20 properties: endpoint: @@ -68,8 +69,11 @@ properties: - const: 1 - const: 2 =20 + link-frequencies: true + required: - data-lanes + - link-frequencies =20 required: - compatible diff --git a/Documentation/devicetree/bindings/memory-controllers/mediatek,= smi-common.yaml b/Documentation/devicetree/bindings/memory-controllers/medi= atek,smi-common.yaml index 3a82b0b27fa0..4fca71f34310 100644 --- a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-com= mon.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-com= mon.yaml @@ -88,10 +88,9 @@ allOf: - mediatek,mt2701-smi-common then: properties: - clock: - items: - minItems: 3 - maxItems: 3 + clocks: + minItems: 3 + maxItems: 3 clock-names: items: - const: apb @@ -108,10 +107,9 @@ allOf: required: - mediatek,smi properties: - clock: - items: - minItems: 3 - maxItems: 3 + clocks: + minItems: 3 + maxItems: 3 clock-names: items: - const: apb @@ -133,10 +131,9 @@ allOf: =20 then: properties: - clock: - items: - minItems: 4 - maxItems: 4 + clocks: + minItems: 4 + maxItems: 4 clock-names: items: - const: apb @@ -146,10 +143,9 @@ allOf: =20 else: # for gen2 HW that don't have gals properties: - clock: - items: - minItems: 2 - maxItems: 2 + clocks: + minItems: 2 + maxItems: 2 clock-names: items: - const: apb diff --git a/Documentation/devicetree/bindings/memory-controllers/mediatek,= smi-larb.yaml b/Documentation/devicetree/bindings/memory-controllers/mediat= ek,smi-larb.yaml index eaeff1ada7f8..c5c32c910045 100644 --- a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-lar= b.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-lar= b.yaml @@ -79,11 +79,11 @@ allOf: =20 then: properties: - clock: - items: - minItems: 3 - maxItems: 3 + clocks: + minItems: 2 + maxItems: 3 clock-names: + minItems: 2 items: - const: apb - const: smi @@ -91,10 +91,9 @@ allOf: =20 else: properties: - clock: - items: - minItems: 2 - maxItems: 2 + clocks: + minItems: 2 + maxItems: 2 clock-names: items: - const: apb @@ -108,7 +107,6 @@ allOf: - mediatek,mt2701-smi-larb - mediatek,mt2712-smi-larb - mediatek,mt6779-smi-larb - - mediatek,mt8167-smi-larb - mediatek,mt8192-smi-larb - mediatek,mt8195-smi-larb =20 diff --git a/Documentation/devicetree/bindings/mtd/nand-controller.yaml b/D= ocumentation/devicetree/bindings/mtd/nand-controller.yaml index bd217e6f5018..5cd144a9ec99 100644 --- a/Documentation/devicetree/bindings/mtd/nand-controller.yaml +++ b/Documentation/devicetree/bindings/mtd/nand-controller.yaml @@ -55,7 +55,7 @@ patternProperties: properties: reg: description: - Contains the native Ready/Busy IDs. + Contains the chip-select IDs. =20 nand-ecc-engine: allOf: @@ -184,7 +184,7 @@ examples: nand-use-soft-ecc-engine; nand-ecc-algo =3D "bch"; =20 - /* controller specific properties */ + /* NAND chip specific properties */ }; =20 nand@1 { diff --git a/Documentation/devicetree/bindings/pinctrl/microchip,sparx5-sgp= io.yaml b/Documentation/devicetree/bindings/pinctrl/microchip,sparx5-sgpio.= yaml index cb554084bdf1..0df4e114fdd6 100644 --- a/Documentation/devicetree/bindings/pinctrl/microchip,sparx5-sgpio.yaml +++ b/Documentation/devicetree/bindings/pinctrl/microchip,sparx5-sgpio.yaml @@ -145,7 +145,7 @@ examples: clocks =3D <&sys_clk>; pinctrl-0 =3D <&sgpio2_pins>; pinctrl-names =3D "default"; - reg =3D <0x1101059c 0x100>; + reg =3D <0x1101059c 0x118>; microchip,sgpio-port-ranges =3D <0 0>, <16 18>, <28 31>; bus-frequency =3D <25000000>; sgpio_in2: gpio@0 { diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad.yam= l b/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad.yaml index 35a8045b2c70..53627c6e2ae3 100644 --- a/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad.yaml +++ b/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad.yaml @@ -106,7 +106,7 @@ examples: dma-names =3D "rx", "tx"; =20 flash@0 { - compatible =3D "spi-nor"; + compatible =3D "jedec,spi-nor"; reg =3D <0>; spi-max-frequency =3D <104000000>; spi-tx-bus-width =3D <2>; diff --git a/Documentation/devicetree/bindings/spi/spi-mxic.txt b/Documenta= tion/devicetree/bindings/spi/spi-mxic.txt index 529f2dab2648..7bcbb229b78b 100644 --- a/Documentation/devicetree/bindings/spi/spi-mxic.txt +++ b/Documentation/devicetree/bindings/spi/spi-mxic.txt @@ -8,11 +8,13 @@ Required properties: - reg: should contain 2 entries, one for the registers and one for the dir= ect mapping area - reg-names: should contain "regs" and "dirmap" -- interrupts: interrupt line connected to the SPI controller - clock-names: should contain "ps_clk", "send_clk" and "send_dly_clk" - clocks: should contain 3 entries for the "ps_clk", "send_clk" and "send_dly_clk" clocks =20 +Optional properties: +- interrupts: interrupt line connected to the SPI controller + Example: =20 spi@43c30000 { diff --git a/Documentation/devicetree/bindings/usb/usb-hcd.yaml b/Documenta= tion/devicetree/bindings/usb/usb-hcd.yaml index 56853c17af66..1dc3d5d7b44f 100644 --- a/Documentation/devicetree/bindings/usb/usb-hcd.yaml +++ b/Documentation/devicetree/bindings/usb/usb-hcd.yaml @@ -33,7 +33,7 @@ patternProperties: "^.*@[0-9a-f]{1,2}$": description: The hard wired USB devices type: object - $ref: /usb/usb-device.yaml + $ref: /schemas/usb/usb-device.yaml =20 additionalProperties: true =20 diff --git a/Documentation/process/stable-kernel-rules.rst b/Documentation/= process/stable-kernel-rules.rst index 003c865e9c21..fbcb48bc2a90 100644 --- a/Documentation/process/stable-kernel-rules.rst +++ b/Documentation/process/stable-kernel-rules.rst @@ -168,7 +168,16 @@ Trees - The finalized and tagged releases of all stable kernels can be found in separate branches per version at: =20 - https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git + https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git + + - The release candidate of all stable kernel versions can be found at: + + https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stabl= e-rc.git/ + + .. warning:: + The -stable-rc tree is a snapshot in time of the stable-queue tree a= nd + will change frequently, hence will be rebased often. It should only = be + used for testing purposes (e.g. to be consumed by CI systems). =20 =20 Review committee diff --git a/Documentation/security/SCTP.rst b/Documentation/security/SCTP.= rst index d5fd6ccc3dcb..b73eb764a001 100644 --- a/Documentation/security/SCTP.rst +++ b/Documentation/security/SCTP.rst @@ -15,10 +15,7 @@ For security module support, three SCTP specific hooks h= ave been implemented:: security_sctp_assoc_request() security_sctp_bind_connect() security_sctp_sk_clone() - -Also the following security hook has been utilised:: - - security_inet_conn_established() + security_sctp_assoc_established() =20 The usage of these hooks are described below with the SELinux implementati= on described in the `SCTP SELinux Support`_ chapter. @@ -122,11 +119,12 @@ calls **sctp_peeloff**\(3). @newsk - pointer to new sock structure. =20 =20 -security_inet_conn_established() -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Called when a COOKIE ACK is received:: +security_sctp_assoc_established() +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Called when a COOKIE ACK is received, and the peer secid will be +saved into ``@asoc->peer_secid`` for client:: =20 - @sk - pointer to sock structure. + @asoc - pointer to sctp association structure. @skb - pointer to skbuff of the COOKIE ACK packet. =20 =20 @@ -134,7 +132,7 @@ Security Hooks used for Association Establishment ------------------------------------------------- =20 The following diagram shows the use of ``security_sctp_bind_connect()``, -``security_sctp_assoc_request()``, ``security_inet_conn_established()`` wh= en +``security_sctp_assoc_request()``, ``security_sctp_assoc_established()`` w= hen establishing an association. :: =20 @@ -172,7 +170,7 @@ establishing an association. <------------------------------------------- COOKIE ACK | | sctp_sf_do_5_1E_ca | - Call security_inet_conn_established() | + Call security_sctp_assoc_established() | to set the peer label. | | | | If SCTP_SOCKET_TCP or peeled off @@ -198,7 +196,7 @@ hooks with the SELinux specifics expanded below:: security_sctp_assoc_request() security_sctp_bind_connect() security_sctp_sk_clone() - security_inet_conn_established() + security_sctp_assoc_established() =20 =20 security_sctp_assoc_request() @@ -271,12 +269,12 @@ sockets sid and peer sid to that contained in the ``@= asoc sid`` and @newsk - pointer to new sock structure. =20 =20 -security_inet_conn_established() -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +security_sctp_assoc_established() +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Called when a COOKIE ACK is received where it sets the connection's peer s= id to that in ``@skb``:: =20 - @sk - pointer to sock structure. + @asoc - pointer to sctp association structure. @skb - pointer to skbuff of the COOKIE ACK packet. =20 =20 diff --git a/Documentation/sound/hd-audio/models.rst b/Documentation/sound/= hd-audio/models.rst index d25335993e55..9b52f50a6854 100644 --- a/Documentation/sound/hd-audio/models.rst +++ b/Documentation/sound/hd-audio/models.rst @@ -261,6 +261,10 @@ alc-sense-combo huawei-mbx-stereo Enable initialization verbs for Huawei MBX stereo speakers; might be risky, try this at your own risk +alc298-samsung-headphone + Samsung laptops with ALC298 +alc256-samsung-headphone + Samsung laptops with ALC256 =20 ALC66x/67x/892 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D diff --git a/Documentation/sphinx/requirements.txt b/Documentation/sphinx/r= equirements.txt index 9a35f50798a6..2c573541ab71 100644 --- a/Documentation/sphinx/requirements.txt +++ b/Documentation/sphinx/requirements.txt @@ -1,2 +1,4 @@ +# jinja2>=3D3.1 is not compatible with Sphinx<4.0 +jinja2<3.1 sphinx_rtd_theme Sphinx=3D=3D2.4.4 diff --git a/MAINTAINERS b/MAINTAINERS index dd36acc87ce6..af9530d98717 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16147,8 +16147,7 @@ REALTEK RTL83xx SMI DSA ROUTER CHIPS M: Linus Walleij S: Maintained F: Documentation/devicetree/bindings/net/dsa/realtek-smi.txt -F: drivers/net/dsa/realtek-smi* -F: drivers/net/dsa/rtl83* +F: drivers/net/dsa/realtek/* =20 REALTEK WIRELESS DRIVER (rtlwifi family) M: Ping-Ke Shih diff --git a/Makefile b/Makefile index f47cecba0618..c16a8a2ffd73 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION =3D 5 PATCHLEVEL =3D 16 -SUBLEVEL =3D 18 +SUBLEVEL =3D 19 EXTRAVERSION =3D NAME =3D Gobble Gobble =20 diff --git a/arch/Kconfig b/arch/Kconfig index d3c4ab249e9c..a825f8251f3d 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -1159,6 +1159,7 @@ config HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET config RANDOMIZE_KSTACK_OFFSET_DEFAULT bool "Randomize kernel stack offset on syscall entry" depends on HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET + depends on INIT_STACK_NONE || !CC_IS_CLANG || CLANG_VERSION >=3D 140000 help The kernel stack offset can be randomized (after pt_regs) by roughly 5 bits of entropy, frustrating memory corruption diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c index 8e90052f6f05..5f7f5aab361f 100644 --- a/arch/arc/kernel/process.c +++ b/arch/arc/kernel/process.c @@ -43,7 +43,7 @@ SYSCALL_DEFINE0(arc_gettls) return task_thread_info(current)->thr_ptr; } =20 -SYSCALL_DEFINE3(arc_usr_cmpxchg, int *, uaddr, int, expected, int, new) +SYSCALL_DEFINE3(arc_usr_cmpxchg, int __user *, uaddr, int, expected, int, = new) { struct pt_regs *regs =3D current_pt_regs(); u32 uval; diff --git a/arch/arm/boot/dts/bcm2711.dtsi b/arch/arm/boot/dts/bcm2711.dtsi index 21294f775a20..89af57482bc8 100644 --- a/arch/arm/boot/dts/bcm2711.dtsi +++ b/arch/arm/boot/dts/bcm2711.dtsi @@ -459,12 +459,26 @@ cpus: cpus { #size-cells =3D <0>; enable-method =3D "brcm,bcm2836-smp"; // for ARM 32-bit =20 + /* Source for d/i-cache-line-size and d/i-cache-sets + * https://developer.arm.com/documentation/100095/0003 + * /Level-1-Memory-System/About-the-L1-memory-system?lang=3Den + * Source for d/i-cache-size + * https://www.raspberrypi.com/documentation/computers + * /processors.html#bcm2711 + */ cpu0: cpu@0 { device_type =3D "cpu"; compatible =3D "arm,cortex-a72"; reg =3D <0>; enable-method =3D "spin-table"; cpu-release-addr =3D <0x0 0x000000d8>; + d-cache-size =3D <0x8000>; + d-cache-line-size =3D <64>; + d-cache-sets =3D <256>; // 32KiB(size)/64(line-size)=3D512ways/2-way set + i-cache-size =3D <0xc000>; + i-cache-line-size =3D <64>; + i-cache-sets =3D <256>; // 48KiB(size)/64(line-size)=3D768ways/3-way set + next-level-cache =3D <&l2>; }; =20 cpu1: cpu@1 { @@ -473,6 +487,13 @@ cpu1: cpu@1 { reg =3D <1>; enable-method =3D "spin-table"; cpu-release-addr =3D <0x0 0x000000e0>; + d-cache-size =3D <0x8000>; + d-cache-line-size =3D <64>; + d-cache-sets =3D <256>; // 32KiB(size)/64(line-size)=3D512ways/2-way set + i-cache-size =3D <0xc000>; + i-cache-line-size =3D <64>; + i-cache-sets =3D <256>; // 48KiB(size)/64(line-size)=3D768ways/3-way set + next-level-cache =3D <&l2>; }; =20 cpu2: cpu@2 { @@ -481,6 +502,13 @@ cpu2: cpu@2 { reg =3D <2>; enable-method =3D "spin-table"; cpu-release-addr =3D <0x0 0x000000e8>; + d-cache-size =3D <0x8000>; + d-cache-line-size =3D <64>; + d-cache-sets =3D <256>; // 32KiB(size)/64(line-size)=3D512ways/2-way set + i-cache-size =3D <0xc000>; + i-cache-line-size =3D <64>; + i-cache-sets =3D <256>; // 48KiB(size)/64(line-size)=3D768ways/3-way set + next-level-cache =3D <&l2>; }; =20 cpu3: cpu@3 { @@ -489,6 +517,28 @@ cpu3: cpu@3 { reg =3D <3>; enable-method =3D "spin-table"; cpu-release-addr =3D <0x0 0x000000f0>; + d-cache-size =3D <0x8000>; + d-cache-line-size =3D <64>; + d-cache-sets =3D <256>; // 32KiB(size)/64(line-size)=3D512ways/2-way set + i-cache-size =3D <0xc000>; + i-cache-line-size =3D <64>; + i-cache-sets =3D <256>; // 48KiB(size)/64(line-size)=3D768ways/3-way set + next-level-cache =3D <&l2>; + }; + + /* Source for d/i-cache-line-size and d/i-cache-sets + * https://developer.arm.com/documentation/100095/0003 + * /Level-2-Memory-System/About-the-L2-memory-system?lang=3Den + * Source for d/i-cache-size + * https://www.raspberrypi.com/documentation/computers + * /processors.html#bcm2711 + */ + l2: l2-cache0 { + compatible =3D "cache"; + cache-size =3D <0x100000>; + cache-line-size =3D <64>; + cache-sets =3D <1024>; // 1MiB(size)/64(line-size)=3D16384ways/16-way s= et + cache-level =3D <2>; }; }; =20 diff --git a/arch/arm/boot/dts/bcm2837.dtsi b/arch/arm/boot/dts/bcm2837.dtsi index 0199ec98cd61..5dbdebc46259 100644 --- a/arch/arm/boot/dts/bcm2837.dtsi +++ b/arch/arm/boot/dts/bcm2837.dtsi @@ -40,12 +40,26 @@ cpus: cpus { #size-cells =3D <0>; enable-method =3D "brcm,bcm2836-smp"; // for ARM 32-bit =20 + /* Source for d/i-cache-line-size and d/i-cache-sets + * https://developer.arm.com/documentation/ddi0500/e/level-1-memory-syst= em + * /about-the-l1-memory-system?lang=3Den + * + * Source for d/i-cache-size + * https://magpi.raspberrypi.com/articles/raspberry-pi-3-specs-benchmarks + */ cpu0: cpu@0 { device_type =3D "cpu"; compatible =3D "arm,cortex-a53"; reg =3D <0>; enable-method =3D "spin-table"; cpu-release-addr =3D <0x0 0x000000d8>; + d-cache-size =3D <0x8000>; + d-cache-line-size =3D <64>; + d-cache-sets =3D <128>; // 32KiB(size)/64(line-size)=3D512ways/4-way set + i-cache-size =3D <0x8000>; + i-cache-line-size =3D <64>; + i-cache-sets =3D <256>; // 32KiB(size)/64(line-size)=3D512ways/2-way set + next-level-cache =3D <&l2>; }; =20 cpu1: cpu@1 { @@ -54,6 +68,13 @@ cpu1: cpu@1 { reg =3D <1>; enable-method =3D "spin-table"; cpu-release-addr =3D <0x0 0x000000e0>; + d-cache-size =3D <0x8000>; + d-cache-line-size =3D <64>; + d-cache-sets =3D <128>; // 32KiB(size)/64(line-size)=3D512ways/4-way set + i-cache-size =3D <0x8000>; + i-cache-line-size =3D <64>; + i-cache-sets =3D <256>; // 32KiB(size)/64(line-size)=3D512ways/2-way set + next-level-cache =3D <&l2>; }; =20 cpu2: cpu@2 { @@ -62,6 +83,13 @@ cpu2: cpu@2 { reg =3D <2>; enable-method =3D "spin-table"; cpu-release-addr =3D <0x0 0x000000e8>; + d-cache-size =3D <0x8000>; + d-cache-line-size =3D <64>; + d-cache-sets =3D <128>; // 32KiB(size)/64(line-size)=3D512ways/4-way set + i-cache-size =3D <0x8000>; + i-cache-line-size =3D <64>; + i-cache-sets =3D <256>; // 32KiB(size)/64(line-size)=3D512ways/2-way set + next-level-cache =3D <&l2>; }; =20 cpu3: cpu@3 { @@ -70,6 +98,27 @@ cpu3: cpu@3 { reg =3D <3>; enable-method =3D "spin-table"; cpu-release-addr =3D <0x0 0x000000f0>; + d-cache-size =3D <0x8000>; + d-cache-line-size =3D <64>; + d-cache-sets =3D <128>; // 32KiB(size)/64(line-size)=3D512ways/4-way set + i-cache-size =3D <0x8000>; + i-cache-line-size =3D <64>; + i-cache-sets =3D <256>; // 32KiB(size)/64(line-size)=3D512ways/2-way set + next-level-cache =3D <&l2>; + }; + + /* Source for cache-line-size + cache-sets + * https://developer.arm.com/documentation/ddi0500 + * /e/level-2-memory-system/about-the-l2-memory-system?lang=3Den + * Source for cache-size + * https://datasheets.raspberrypi.com/cm/cm1-and-cm3-datasheet.pdf + */ + l2: l2-cache0 { + compatible =3D "cache"; + cache-size =3D <0x80000>; + cache-line-size =3D <64>; + cache-sets =3D <512>; // 512KiB(size)/64(line-size)=3D8192ways/16-way s= et + cache-level =3D <2>; }; }; }; diff --git a/arch/arm/boot/dts/dra7-l4.dtsi b/arch/arm/boot/dts/dra7-l4.dtsi index 956a26d52a4c..0a11bacffc1f 100644 --- a/arch/arm/boot/dts/dra7-l4.dtsi +++ b/arch/arm/boot/dts/dra7-l4.dtsi @@ -3482,8 +3482,7 @@ timer14: timer@0 { ti,timer-pwm; }; }; - - target-module@2c000 { /* 0x4882c000, ap 17 02.0 */ + timer15_target: target-module@2c000 { /* 0x4882c000, ap 17 02.0 */ compatible =3D "ti,sysc-omap4-timer", "ti,sysc"; reg =3D <0x2c000 0x4>, <0x2c010 0x4>; @@ -3511,7 +3510,7 @@ timer15: timer@0 { }; }; =20 - target-module@2e000 { /* 0x4882e000, ap 19 14.0 */ + timer16_target: target-module@2e000 { /* 0x4882e000, ap 19 14.0 */ compatible =3D "ti,sysc-omap4-timer", "ti,sysc"; reg =3D <0x2e000 0x4>, <0x2e010 0x4>; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index 6b485cbed8d5..8f7ffe2f66e9 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -1339,20 +1339,20 @@ timer@0 { }; =20 /* Local timers, see ARM architected timer wrap erratum i940 */ -&timer3_target { +&timer15_target { ti,no-reset-on-init; ti,no-idle; timer@0 { - assigned-clocks =3D <&l4per_clkctrl DRA7_L4PER_TIMER3_CLKCTRL 24>; + assigned-clocks =3D <&l4per3_clkctrl DRA7_L4PER3_TIMER15_CLKCTRL 24>; assigned-clock-parents =3D <&timer_sys_clk_div>; }; }; =20 -&timer4_target { +&timer16_target { ti,no-reset-on-init; ti,no-idle; timer@0 { - assigned-clocks =3D <&l4per_clkctrl DRA7_L4PER_TIMER4_CLKCTRL 24>; + assigned-clocks =3D <&l4per3_clkctrl DRA7_L4PER3_TIMER16_CLKCTRL 24>; assigned-clock-parents =3D <&timer_sys_clk_div>; }; }; diff --git a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi b/arch/arm/boot/dts/= exynos5250-pinctrl.dtsi index d31a68672bfa..d7d756614edd 100644 --- a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos5250-pinctrl.dtsi @@ -260,7 +260,7 @@ i2c3_hs_bus: i2c3-hs-bus { }; =20 uart3_data: uart3-data { - samsung,pins =3D "gpa1-4", "gpa1-4"; + samsung,pins =3D "gpa1-4", "gpa1-5"; samsung,pin-function =3D ; samsung,pin-pud =3D ; samsung,pin-drv =3D ; diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/= exynos5250-smdk5250.dts index 39bbe18145cf..f042954bdfa5 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts @@ -118,6 +118,9 @@ &hdmi { status =3D "okay"; ddc =3D <&i2c_2>; hpd-gpios =3D <&gpx3 7 GPIO_ACTIVE_HIGH>; + vdd-supply =3D <&ldo8_reg>; + vdd_osc-supply =3D <&ldo10_reg>; + vdd_pll-supply =3D <&ldo8_reg>; }; =20 &i2c_0 { diff --git a/arch/arm/boot/dts/exynos5420-smdk5420.dts b/arch/arm/boot/dts/= exynos5420-smdk5420.dts index a4f0e3ffedbd..07f65213aae6 100644 --- a/arch/arm/boot/dts/exynos5420-smdk5420.dts +++ b/arch/arm/boot/dts/exynos5420-smdk5420.dts @@ -124,6 +124,9 @@ &hdmi { hpd-gpios =3D <&gpx3 7 GPIO_ACTIVE_HIGH>; pinctrl-names =3D "default"; pinctrl-0 =3D <&hdmi_hpd_irq>; + vdd-supply =3D <&ldo6_reg>; + vdd_osc-supply =3D <&ldo7_reg>; + vdd_pll-supply =3D <&ldo6_reg>; }; =20 &hsi2c_4 { diff --git a/arch/arm/boot/dts/imx53-m53menlo.dts b/arch/arm/boot/dts/imx53= -m53menlo.dts index 4f88e96d81dd..d5c68d1ea707 100644 --- a/arch/arm/boot/dts/imx53-m53menlo.dts +++ b/arch/arm/boot/dts/imx53-m53menlo.dts @@ -53,6 +53,31 @@ eth { }; }; =20 + lvds-decoder { + compatible =3D "ti,ds90cf364a", "lvds-decoder"; + + ports { + #address-cells =3D <1>; + #size-cells =3D <0>; + + port@0 { + reg =3D <0>; + + lvds_decoder_in: endpoint { + remote-endpoint =3D <&lvds0_out>; + }; + }; + + port@1 { + reg =3D <1>; + + lvds_decoder_out: endpoint { + remote-endpoint =3D <&panel_in>; + }; + }; + }; + }; + panel { compatible =3D "edt,etm0700g0dh6"; pinctrl-0 =3D <&pinctrl_display_gpio>; @@ -61,7 +86,7 @@ panel { =20 port { panel_in: endpoint { - remote-endpoint =3D <&lvds0_out>; + remote-endpoint =3D <&lvds_decoder_out>; }; }; }; @@ -450,7 +475,7 @@ port@2 { reg =3D <2>; =20 lvds0_out: endpoint { - remote-endpoint =3D <&panel_in>; + remote-endpoint =3D <&lvds_decoder_in>; }; }; }; diff --git a/arch/arm/boot/dts/imx7-colibri.dtsi b/arch/arm/boot/dts/imx7-c= olibri.dtsi index 62b771c1d5a9..f1c60b0cb143 100644 --- a/arch/arm/boot/dts/imx7-colibri.dtsi +++ b/arch/arm/boot/dts/imx7-colibri.dtsi @@ -40,7 +40,7 @@ simple-audio-card,cpu { =20 dailink_master: simple-audio-card,codec { sound-dai =3D <&codec>; - clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; + clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; }; }; }; @@ -293,7 +293,7 @@ codec: sgtl5000@a { compatible =3D "fsl,sgtl5000"; #sound-dai-cells =3D <0>; reg =3D <0x0a>; - clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; + clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; pinctrl-names =3D "default"; pinctrl-0 =3D <&pinctrl_sai1_mclk>; VDDA-supply =3D <®_module_3v3_avdd>; diff --git a/arch/arm/boot/dts/imx7-mba7.dtsi b/arch/arm/boot/dts/imx7-mba7= .dtsi index 49086c6b6a0a..3df6dff7734a 100644 --- a/arch/arm/boot/dts/imx7-mba7.dtsi +++ b/arch/arm/boot/dts/imx7-mba7.dtsi @@ -302,7 +302,7 @@ &i2c2 { tlv320aic32x4: audio-codec@18 { compatible =3D "ti,tlv320aic32x4"; reg =3D <0x18>; - clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; + clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; clock-names =3D "mclk"; ldoin-supply =3D <®_audio_3v3>; iov-supply =3D <®_audio_3v3>; diff --git a/arch/arm/boot/dts/imx7d-nitrogen7.dts b/arch/arm/boot/dts/imx7= d-nitrogen7.dts index e0751e6ba3c0..a31de900139d 100644 --- a/arch/arm/boot/dts/imx7d-nitrogen7.dts +++ b/arch/arm/boot/dts/imx7d-nitrogen7.dts @@ -288,7 +288,7 @@ &i2c4 { codec: wm8960@1a { compatible =3D "wlf,wm8960"; reg =3D <0x1a>; - clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; + clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; clock-names =3D "mclk"; wlf,shared-lrclk; }; diff --git a/arch/arm/boot/dts/imx7d-pico-hobbit.dts b/arch/arm/boot/dts/im= x7d-pico-hobbit.dts index 7b2198a9372c..d917dc4f2f22 100644 --- a/arch/arm/boot/dts/imx7d-pico-hobbit.dts +++ b/arch/arm/boot/dts/imx7d-pico-hobbit.dts @@ -31,7 +31,7 @@ simple-audio-card,cpu { =20 dailink_master: simple-audio-card,codec { sound-dai =3D <&sgtl5000>; - clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; + clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; }; }; }; @@ -41,7 +41,7 @@ sgtl5000: codec@a { #sound-dai-cells =3D <0>; reg =3D <0x0a>; compatible =3D "fsl,sgtl5000"; - clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; + clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; VDDA-supply =3D <®_2p5v>; VDDIO-supply =3D <®_vref_1v8>; }; diff --git a/arch/arm/boot/dts/imx7d-pico-pi.dts b/arch/arm/boot/dts/imx7d-= pico-pi.dts index 70bea95c06d8..f263e391e24c 100644 --- a/arch/arm/boot/dts/imx7d-pico-pi.dts +++ b/arch/arm/boot/dts/imx7d-pico-pi.dts @@ -31,7 +31,7 @@ simple-audio-card,cpu { =20 dailink_master: simple-audio-card,codec { sound-dai =3D <&sgtl5000>; - clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; + clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; }; }; }; @@ -41,7 +41,7 @@ sgtl5000: codec@a { #sound-dai-cells =3D <0>; reg =3D <0x0a>; compatible =3D "fsl,sgtl5000"; - clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; + clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; VDDA-supply =3D <®_2p5v>; VDDIO-supply =3D <®_vref_1v8>; }; diff --git a/arch/arm/boot/dts/imx7d-sdb.dts b/arch/arm/boot/dts/imx7d-sdb.= dts index 7813ef960f6e..f053f5122741 100644 --- a/arch/arm/boot/dts/imx7d-sdb.dts +++ b/arch/arm/boot/dts/imx7d-sdb.dts @@ -385,14 +385,14 @@ &i2c4 { codec: wm8960@1a { compatible =3D "wlf,wm8960"; reg =3D <0x1a>; - clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; + clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; clock-names =3D "mclk"; wlf,shared-lrclk; wlf,hp-cfg =3D <2 2 3>; wlf,gpio-cfg =3D <1 3>; assigned-clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_SRC>, <&clks IMX7D_PLL_AUDIO_POST_DIV>, - <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; + <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; assigned-clock-parents =3D <&clks IMX7D_PLL_AUDIO_POST_DIV>; assigned-clock-rates =3D <0>, <884736000>, <12288000>; }; diff --git a/arch/arm/boot/dts/imx7s-warp.dts b/arch/arm/boot/dts/imx7s-war= p.dts index 569bbd84e371..558b064da743 100644 --- a/arch/arm/boot/dts/imx7s-warp.dts +++ b/arch/arm/boot/dts/imx7s-warp.dts @@ -75,7 +75,7 @@ simple-audio-card,cpu { =20 dailink_master: simple-audio-card,codec { sound-dai =3D <&codec>; - clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; + clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; }; }; }; @@ -232,7 +232,7 @@ codec: sgtl5000@a { #sound-dai-cells =3D <0>; reg =3D <0x0a>; compatible =3D "fsl,sgtl5000"; - clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; + clocks =3D <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; pinctrl-names =3D "default"; pinctrl-0 =3D <&pinctrl_sai1_mclk>; VDDA-supply =3D <&vgen4_reg>; diff --git a/arch/arm/boot/dts/openbmc-flash-layout-64.dtsi b/arch/arm/boot= /dts/openbmc-flash-layout-64.dtsi index 31f59de5190b..7af41361c480 100644 --- a/arch/arm/boot/dts/openbmc-flash-layout-64.dtsi +++ b/arch/arm/boot/dts/openbmc-flash-layout-64.dtsi @@ -28,7 +28,7 @@ rofs@a00000 { label =3D "rofs"; }; =20 - rwfs@6000000 { + rwfs@2a00000 { reg =3D <0x2a00000 0x1600000>; // 22MB label =3D "rwfs"; }; diff --git a/arch/arm/boot/dts/openbmc-flash-layout.dtsi b/arch/arm/boot/dt= s/openbmc-flash-layout.dtsi index 6c26524e93e1..b47e14063c38 100644 --- a/arch/arm/boot/dts/openbmc-flash-layout.dtsi +++ b/arch/arm/boot/dts/openbmc-flash-layout.dtsi @@ -20,7 +20,7 @@ kernel@80000 { label =3D "kernel"; }; =20 - rofs@c0000 { + rofs@4c0000 { reg =3D <0x4c0000 0x1740000>; label =3D "rofs"; }; diff --git a/arch/arm/boot/dts/qcom-ipq4019.dtsi b/arch/arm/boot/dts/qcom-i= pq4019.dtsi index ff1bdb10ad19..08bc5f46649d 100644 --- a/arch/arm/boot/dts/qcom-ipq4019.dtsi +++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi @@ -142,7 +142,8 @@ pmu { clocks { sleep_clk: sleep_clk { compatible =3D "fixed-clock"; - clock-frequency =3D <32768>; + clock-frequency =3D <32000>; + clock-output-names =3D "gcc_sleep_clk_src"; #clock-cells =3D <0>; }; =20 diff --git a/arch/arm/boot/dts/qcom-msm8960.dtsi b/arch/arm/boot/dts/qcom-m= sm8960.dtsi index 2a0ec97a264f..a0f9ab7f08f3 100644 --- a/arch/arm/boot/dts/qcom-msm8960.dtsi +++ b/arch/arm/boot/dts/qcom-msm8960.dtsi @@ -146,7 +146,9 @@ rpm@108000 { reg =3D <0x108000 0x1000>; qcom,ipc =3D <&l2cc 0x8 2>; =20 - interrupts =3D <0 19 0>, <0 21 0>, <0 22 0>; + interrupts =3D , + , + ; interrupt-names =3D "ack", "err", "wakeup"; =20 regulators { @@ -192,7 +194,7 @@ gsbi5_serial: serial@16440000 { compatible =3D "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; reg =3D <0x16440000 0x1000>, <0x16400000 0x1000>; - interrupts =3D <0 154 0x0>; + interrupts =3D ; clocks =3D <&gcc GSBI5_UART_CLK>, <&gcc GSBI5_H_CLK>; clock-names =3D "core", "iface"; status =3D "disabled"; @@ -318,7 +320,7 @@ spi@16080000 { #address-cells =3D <1>; #size-cells =3D <0>; reg =3D <0x16080000 0x1000>; - interrupts =3D <0 147 0>; + interrupts =3D ; spi-max-frequency =3D <24000000>; cs-gpios =3D <&msmgpio 8 0>; =20 diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 801969c113d6..de88eb484718 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -413,7 +413,7 @@ hsmc: hsmc@f8014000 { pmecc: ecc-engine@f8014070 { compatible =3D "atmel,sama5d2-pmecc"; reg =3D <0xf8014070 0x490>, - <0xf8014500 0x100>; + <0xf8014500 0x200>; }; }; =20 diff --git a/arch/arm/boot/dts/sama7g5.dtsi b/arch/arm/boot/dts/sama7g5.dtsi index 7039311bf678..91797323f04c 100644 --- a/arch/arm/boot/dts/sama7g5.dtsi +++ b/arch/arm/boot/dts/sama7g5.dtsi @@ -352,8 +352,6 @@ i2c1: i2c@600 { dmas =3D <&dma0 AT91_XDMAC_DT_PERID(7)>, <&dma0 AT91_XDMAC_DT_PERID(8)>; dma-names =3D "rx", "tx"; - atmel,use-dma-rx; - atmel,use-dma-tx; status =3D "disabled"; }; }; @@ -528,8 +526,6 @@ i2c8: i2c@600 { dmas =3D <&dma0 AT91_XDMAC_DT_PERID(21)>, <&dma0 AT91_XDMAC_DT_PERID(22)>; dma-names =3D "rx", "tx"; - atmel,use-dma-rx; - atmel,use-dma-tx; status =3D "disabled"; }; }; @@ -554,8 +550,6 @@ i2c9: i2c@600 { dmas =3D <&dma0 AT91_XDMAC_DT_PERID(23)>, <&dma0 AT91_XDMAC_DT_PERID(24)>; dma-names =3D "rx", "tx"; - atmel,use-dma-rx; - atmel,use-dma-tx; status =3D "disabled"; }; }; diff --git a/arch/arm/boot/dts/spear1340.dtsi b/arch/arm/boot/dts/spear1340= .dtsi index 827e887afbda..13e1bdb3ddbf 100644 --- a/arch/arm/boot/dts/spear1340.dtsi +++ b/arch/arm/boot/dts/spear1340.dtsi @@ -134,9 +134,9 @@ serial@b4100000 { reg =3D <0xb4100000 0x1000>; interrupts =3D <0 105 0x4>; status =3D "disabled"; - dmas =3D <&dwdma0 12 0 1>, - <&dwdma0 13 1 0>; - dma-names =3D "tx", "rx"; + dmas =3D <&dwdma0 13 0 1>, + <&dwdma0 12 1 0>; + dma-names =3D "rx", "tx"; }; =20 thermal@e07008c4 { diff --git a/arch/arm/boot/dts/spear13xx.dtsi b/arch/arm/boot/dts/spear13xx= .dtsi index c87b881b2c8b..913553367687 100644 --- a/arch/arm/boot/dts/spear13xx.dtsi +++ b/arch/arm/boot/dts/spear13xx.dtsi @@ -284,9 +284,9 @@ spi0: spi@e0100000 { #size-cells =3D <0>; interrupts =3D <0 31 0x4>; status =3D "disabled"; - dmas =3D <&dwdma0 4 0 0>, - <&dwdma0 5 0 0>; - dma-names =3D "tx", "rx"; + dmas =3D <&dwdma0 5 0 0>, + <&dwdma0 4 0 0>; + dma-names =3D "rx", "tx"; }; =20 rtc@e0580000 { diff --git a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi b/arch/arm/boot/dts/s= tm32mp15-pinctrl.dtsi index 2ebafe27a865..d3553e0f0187 100644 --- a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi +++ b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi @@ -1190,7 +1190,7 @@ pins { }; }; =20 - sai2a_sleep_pins_c: sai2a-2 { + sai2a_sleep_pins_c: sai2a-sleep-2 { pins { pinmux =3D , /* SAI2_SCK_A */ , /* SAI2_SD_A */ diff --git a/arch/arm/boot/dts/sun8i-v3s.dtsi b/arch/arm/boot/dts/sun8i-v3s= .dtsi index b30bc1a25ebb..084323d5c61c 100644 --- a/arch/arm/boot/dts/sun8i-v3s.dtsi +++ b/arch/arm/boot/dts/sun8i-v3s.dtsi @@ -593,6 +593,17 @@ spi0: spi@1c68000 { #size-cells =3D <0>; }; =20 + gic: interrupt-controller@1c81000 { + compatible =3D "arm,gic-400"; + reg =3D <0x01c81000 0x1000>, + <0x01c82000 0x2000>, + <0x01c84000 0x2000>, + <0x01c86000 0x2000>; + interrupt-controller; + #interrupt-cells =3D <3>; + interrupts =3D ; + }; + csi1: camera@1cb4000 { compatible =3D "allwinner,sun8i-v3s-csi"; reg =3D <0x01cb4000 0x3000>; @@ -604,16 +615,5 @@ csi1: camera@1cb4000 { resets =3D <&ccu RST_BUS_CSI>; status =3D "disabled"; }; - - gic: interrupt-controller@1c81000 { - compatible =3D "arm,gic-400"; - reg =3D <0x01c81000 0x1000>, - <0x01c82000 0x2000>, - <0x01c84000 0x2000>, - <0x01c86000 0x2000>; - interrupt-controller; - #interrupt-cells =3D <3>; - interrupts =3D ; - }; }; }; diff --git a/arch/arm/boot/dts/tegra20-tamonten.dtsi b/arch/arm/boot/dts/te= gra20-tamonten.dtsi index dd4d506683de..7f14f0d005c3 100644 --- a/arch/arm/boot/dts/tegra20-tamonten.dtsi +++ b/arch/arm/boot/dts/tegra20-tamonten.dtsi @@ -183,8 +183,8 @@ uca { }; conf_ata { nvidia,pins =3D "ata", "atb", "atc", "atd", "ate", - "cdev1", "cdev2", "dap1", "dtb", "gma", - "gmb", "gmc", "gmd", "gme", "gpu7", + "cdev1", "cdev2", "dap1", "dtb", "dtf", + "gma", "gmb", "gmc", "gmd", "gme", "gpu7", "gpv", "i2cp", "irrx", "irtx", "pta", "rm", "slxa", "slxk", "spia", "spib", "uac"; @@ -203,7 +203,7 @@ conf_csus { }; conf_crtp { nvidia,pins =3D "crtp", "dap2", "dap3", "dap4", - "dtc", "dte", "dtf", "gpu", "sdio1", + "dtc", "dte", "gpu", "sdio1", "slxc", "slxd", "spdi", "spdo", "spig", "uda"; nvidia,pull =3D ; diff --git a/arch/arm/configs/multi_v5_defconfig b/arch/arm/configs/multi_v= 5_defconfig index fe8d760256a4..3e3beb0cc33d 100644 --- a/arch/arm/configs/multi_v5_defconfig +++ b/arch/arm/configs/multi_v5_defconfig @@ -188,6 +188,7 @@ CONFIG_REGULATOR=3Dy CONFIG_REGULATOR_FIXED_VOLTAGE=3Dy CONFIG_MEDIA_SUPPORT=3Dy CONFIG_MEDIA_CAMERA_SUPPORT=3Dy +CONFIG_MEDIA_PLATFORM_SUPPORT=3Dy CONFIG_V4L_PLATFORM_DRIVERS=3Dy CONFIG_VIDEO_ASPEED=3Dm CONFIG_VIDEO_ATMEL_ISI=3Dm @@ -196,6 +197,7 @@ CONFIG_DRM_ATMEL_HLCDC=3Dm CONFIG_DRM_PANEL_SIMPLE=3Dy CONFIG_DRM_PANEL_EDP=3Dy CONFIG_DRM_ASPEED_GFX=3Dm +CONFIG_FB=3Dy CONFIG_FB_IMX=3Dy CONFIG_FB_ATMEL=3Dy CONFIG_BACKLIGHT_ATMEL_LCDC=3Dy diff --git a/arch/arm/crypto/Kconfig b/arch/arm/crypto/Kconfig index 2b575792363e..e4dba5461cb3 100644 --- a/arch/arm/crypto/Kconfig +++ b/arch/arm/crypto/Kconfig @@ -102,6 +102,8 @@ config CRYPTO_AES_ARM_BS depends on KERNEL_MODE_NEON select CRYPTO_SKCIPHER select CRYPTO_LIB_AES + select CRYPTO_AES + select CRYPTO_CBC select CRYPTO_SIMD help Use a faster and more secure NEON based implementation of AES in CBC, diff --git a/arch/arm/kernel/entry-ftrace.S b/arch/arm/kernel/entry-ftrace.S index a74289ebc803..5f1b1ce10473 100644 --- a/arch/arm/kernel/entry-ftrace.S +++ b/arch/arm/kernel/entry-ftrace.S @@ -22,10 +22,7 @@ * mcount can be thought of as a function called in the middle of a subrou= tine * call. As such, it needs to be transparent for both the caller and the * callee: the original lr needs to be restored when leaving mcount, and no - * registers should be clobbered. (In the __gnu_mcount_nc implementation,= we - * clobber the ip register. This is OK because the ARM calling convention - * allows it to be clobbered in subroutines and doesn't use it to hold - * parameters.) + * registers should be clobbered. * * When using dynamic ftrace, we patch out the mcount call by a "pop {lr}" * instead of the __gnu_mcount_nc call (see arch/arm/kernel/ftrace.c). @@ -70,26 +67,25 @@ =20 .macro __ftrace_regs_caller =20 - sub sp, sp, #8 @ space for PC and CPSR OLD_R0, + str lr, [sp, #-8]! @ store LR as PC and make space for CPSR/OLD_R0, @ OLD_R0 will overwrite previous LR =20 - add ip, sp, #12 @ move in IP the value of SP as it was - @ before the push {lr} of the mcount mechanism + ldr lr, [sp, #8] @ get previous LR =20 - str lr, [sp, #0] @ store LR instead of PC + str r0, [sp, #8] @ write r0 as OLD_R0 over previous LR =20 - ldr lr, [sp, #8] @ get previous LR + str lr, [sp, #-4]! @ store previous LR as LR =20 - str r0, [sp, #8] @ write r0 as OLD_R0 over previous LR + add lr, sp, #16 @ move in LR the value of SP as it was + @ before the push {lr} of the mcount mechanism =20 - stmdb sp!, {ip, lr} - stmdb sp!, {r0-r11, lr} + push {r0-r11, ip, lr} =20 @ stack content at this point: @ 0 4 48 52 56 60 64 68 72 - @ R0 | R1 | ... | LR | SP + 4 | previous LR | LR | PSR | OLD_R0 | + @ R0 | R1 | ... | IP | SP + 4 | previous LR | LR | PSR | OLD_R0 | =20 - mov r3, sp @ struct pt_regs* + mov r3, sp @ struct pt_regs* =20 ldr r2, =3Dfunction_trace_op ldr r2, [r2] @ pointer to the current @@ -112,11 +108,9 @@ ftrace_graph_regs_call: #endif =20 @ pop saved regs - ldmia sp!, {r0-r12} @ restore r0 through r12 - ldr ip, [sp, #8] @ restore PC - ldr lr, [sp, #4] @ restore LR - ldr sp, [sp, #0] @ restore SP - mov pc, ip @ return + pop {r0-r11, ip, lr} @ restore r0 through r12 + ldr lr, [sp], #4 @ restore LR + ldr pc, [sp], #12 .endm =20 #ifdef CONFIG_FUNCTION_GRAPH_TRACER @@ -132,11 +126,9 @@ ftrace_graph_regs_call: bl prepare_ftrace_return =20 @ pop registers saved in ftrace_regs_caller - ldmia sp!, {r0-r12} @ restore r0 through r12 - ldr ip, [sp, #8] @ restore PC - ldr lr, [sp, #4] @ restore LR - ldr sp, [sp, #0] @ restore SP - mov pc, ip @ return + pop {r0-r11, ip, lr} @ restore r0 through r12 + ldr lr, [sp], #4 @ restore LR + ldr pc, [sp], #12 =20 .endm #endif @@ -202,16 +194,17 @@ ftrace_graph_call\suffix: .endm =20 .macro mcount_exit - ldmia sp!, {r0-r3, ip, lr} - ret ip + ldmia sp!, {r0-r3} + ldr lr, [sp, #4] + ldr pc, [sp], #8 .endm =20 ENTRY(__gnu_mcount_nc) UNWIND(.fnstart) #ifdef CONFIG_DYNAMIC_FTRACE - mov ip, lr - ldmia sp!, {lr} - ret ip + push {lr} + ldr lr, [sp, #4] + ldr pc, [sp], #8 #else __mcount #endif diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c index 6166ba38bf99..b74bfcf94fb1 100644 --- a/arch/arm/kernel/swp_emulate.c +++ b/arch/arm/kernel/swp_emulate.c @@ -195,7 +195,7 @@ static int swp_handler(struct pt_regs *regs, unsigned i= nt instr) destreg, EXTRACT_REG_NUM(instr, RT2_OFFSET), data); =20 /* Check access in reasonable access range for both SWP and SWPB */ - if (!access_ok((address & ~3), 4)) { + if (!access_ok((void __user *)(address & ~3), 4)) { pr_debug("SWP{B} emulation: access to %p not allowed!\n", (void *)address); res =3D -EFAULT; diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 90c887aa67a4..f74460d3bef5 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -575,7 +575,7 @@ do_cache_op(unsigned long start, unsigned long end, int= flags) if (end < start || flags) return -EINVAL; =20 - if (!access_ok(start, end - start)) + if (!access_ok((void __user *)start, end - start)) return -EFAULT; =20 return __do_cache_op(start, end); diff --git a/arch/arm/mach-iop32x/include/mach/entry-macro.S b/arch/arm/mac= h-iop32x/include/mach/entry-macro.S index 8e6766d4621e..341e5d9a6616 100644 --- a/arch/arm/mach-iop32x/include/mach/entry-macro.S +++ b/arch/arm/mach-iop32x/include/mach/entry-macro.S @@ -20,7 +20,7 @@ mrc p6, 0, \irqstat, c8, c0, 0 @ Read IINTSRC cmp \irqstat, #0 clzne \irqnr, \irqstat - rsbne \irqnr, \irqnr, #31 + rsbne \irqnr, \irqnr, #32 .endm =20 .macro arch_ret_to_user, tmp1, tmp2 diff --git a/arch/arm/mach-iop32x/include/mach/irqs.h b/arch/arm/mach-iop32= x/include/mach/irqs.h index c4e78df428e8..e09ae5f48aec 100644 --- a/arch/arm/mach-iop32x/include/mach/irqs.h +++ b/arch/arm/mach-iop32x/include/mach/irqs.h @@ -9,6 +9,6 @@ #ifndef __IRQS_H #define __IRQS_H =20 -#define NR_IRQS 32 +#define NR_IRQS 33 =20 #endif diff --git a/arch/arm/mach-iop32x/irq.c b/arch/arm/mach-iop32x/irq.c index 2d48bf1398c1..d1e8824cbd82 100644 --- a/arch/arm/mach-iop32x/irq.c +++ b/arch/arm/mach-iop32x/irq.c @@ -32,14 +32,14 @@ static void intstr_write(u32 val) static void iop32x_irq_mask(struct irq_data *d) { - iop32x_mask &=3D ~(1 << d->irq); + iop32x_mask &=3D ~(1 << (d->irq - 1)); intctl_write(iop32x_mask); } =20 static void iop32x_irq_unmask(struct irq_data *d) { - iop32x_mask |=3D 1 << d->irq; + iop32x_mask |=3D 1 << (d->irq - 1); intctl_write(iop32x_mask); } =20 @@ -65,7 +65,7 @@ void __init iop32x_init_irq(void) machine_is_em7210()) *IOP3XX_PCIIRSR =3D 0x0f; =20 - for (i =3D 0; i < NR_IRQS; i++) { + for (i =3D 1; i < NR_IRQS; i++) { irq_set_chip_and_handler(i, &ext_chip, handle_level_irq); irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE); } diff --git a/arch/arm/mach-iop32x/irqs.h b/arch/arm/mach-iop32x/irqs.h index 69858e4e905d..e1dfc8b4e7d7 100644 --- a/arch/arm/mach-iop32x/irqs.h +++ b/arch/arm/mach-iop32x/irqs.h @@ -7,36 +7,40 @@ #ifndef __IOP32X_IRQS_H #define __IOP32X_IRQS_H =20 +/* Interrupts in Linux start at 1, hardware starts at 0 */ + +#define IOP_IRQ(x) ((x) + 1) + /* * IOP80321 chipset interrupts */ -#define IRQ_IOP32X_DMA0_EOT 0 -#define IRQ_IOP32X_DMA0_EOC 1 -#define IRQ_IOP32X_DMA1_EOT 2 -#define IRQ_IOP32X_DMA1_EOC 3 -#define IRQ_IOP32X_AA_EOT 6 -#define IRQ_IOP32X_AA_EOC 7 -#define IRQ_IOP32X_CORE_PMON 8 -#define IRQ_IOP32X_TIMER0 9 -#define IRQ_IOP32X_TIMER1 10 -#define IRQ_IOP32X_I2C_0 11 -#define IRQ_IOP32X_I2C_1 12 -#define IRQ_IOP32X_MESSAGING 13 -#define IRQ_IOP32X_ATU_BIST 14 -#define IRQ_IOP32X_PERFMON 15 -#define IRQ_IOP32X_CORE_PMU 16 -#define IRQ_IOP32X_BIU_ERR 17 -#define IRQ_IOP32X_ATU_ERR 18 -#define IRQ_IOP32X_MCU_ERR 19 -#define IRQ_IOP32X_DMA0_ERR 20 -#define IRQ_IOP32X_DMA1_ERR 21 -#define IRQ_IOP32X_AA_ERR 23 -#define IRQ_IOP32X_MSG_ERR 24 -#define IRQ_IOP32X_SSP 25 -#define IRQ_IOP32X_XINT0 27 -#define IRQ_IOP32X_XINT1 28 -#define IRQ_IOP32X_XINT2 29 -#define IRQ_IOP32X_XINT3 30 -#define IRQ_IOP32X_HPI 31 +#define IRQ_IOP32X_DMA0_EOT IOP_IRQ(0) +#define IRQ_IOP32X_DMA0_EOC IOP_IRQ(1) +#define IRQ_IOP32X_DMA1_EOT IOP_IRQ(2) +#define IRQ_IOP32X_DMA1_EOC IOP_IRQ(3) +#define IRQ_IOP32X_AA_EOT IOP_IRQ(6) +#define IRQ_IOP32X_AA_EOC IOP_IRQ(7) +#define IRQ_IOP32X_CORE_PMON IOP_IRQ(8) +#define IRQ_IOP32X_TIMER0 IOP_IRQ(9) +#define IRQ_IOP32X_TIMER1 IOP_IRQ(10) +#define IRQ_IOP32X_I2C_0 IOP_IRQ(11) +#define IRQ_IOP32X_I2C_1 IOP_IRQ(12) +#define IRQ_IOP32X_MESSAGING IOP_IRQ(13) +#define IRQ_IOP32X_ATU_BIST IOP_IRQ(14) +#define IRQ_IOP32X_PERFMON IOP_IRQ(15) +#define IRQ_IOP32X_CORE_PMU IOP_IRQ(16) +#define IRQ_IOP32X_BIU_ERR IOP_IRQ(17) +#define IRQ_IOP32X_ATU_ERR IOP_IRQ(18) +#define IRQ_IOP32X_MCU_ERR IOP_IRQ(19) +#define IRQ_IOP32X_DMA0_ERR IOP_IRQ(20) +#define IRQ_IOP32X_DMA1_ERR IOP_IRQ(21) +#define IRQ_IOP32X_AA_ERR IOP_IRQ(23) +#define IRQ_IOP32X_MSG_ERR IOP_IRQ(24) +#define IRQ_IOP32X_SSP IOP_IRQ(25) +#define IRQ_IOP32X_XINT0 IOP_IRQ(27) +#define IRQ_IOP32X_XINT1 IOP_IRQ(28) +#define IRQ_IOP32X_XINT2 IOP_IRQ(29) +#define IRQ_IOP32X_XINT3 IOP_IRQ(30) +#define IRQ_IOP32X_HPI IOP_IRQ(31) =20 #endif diff --git a/arch/arm/mach-mmp/sram.c b/arch/arm/mach-mmp/sram.c index 6794e2db1ad5..ecc46c31004f 100644 --- a/arch/arm/mach-mmp/sram.c +++ b/arch/arm/mach-mmp/sram.c @@ -72,6 +72,8 @@ static int sram_probe(struct platform_device *pdev) if (!info) return -ENOMEM; =20 + platform_set_drvdata(pdev, info); + res =3D platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res =3D=3D NULL) { dev_err(&pdev->dev, "no memory resource defined\n"); @@ -107,8 +109,6 @@ static int sram_probe(struct platform_device *pdev) list_add(&info->node, &sram_bank_list); mutex_unlock(&sram_lock); =20 - platform_set_drvdata(pdev, info); - dev_info(&pdev->dev, "initialized\n"); return 0; =20 @@ -127,17 +127,19 @@ static int sram_remove(struct platform_device *pdev) struct sram_bank_info *info; =20 info =3D platform_get_drvdata(pdev); - if (info =3D=3D NULL) - return -ENODEV; =20 - mutex_lock(&sram_lock); - list_del(&info->node); - mutex_unlock(&sram_lock); + if (info->sram_size) { + mutex_lock(&sram_lock); + list_del(&info->node); + mutex_unlock(&sram_lock); + + gen_pool_destroy(info->gpool); + iounmap(info->sram_virt); + kfree(info->pool_name); + } =20 - gen_pool_destroy(info->gpool); - iounmap(info->sram_virt); - kfree(info->pool_name); kfree(info); + return 0; } =20 diff --git a/arch/arm/mach-mstar/Kconfig b/arch/arm/mach-mstar/Kconfig index cd300eeedc20..0bf4d312bcfd 100644 --- a/arch/arm/mach-mstar/Kconfig +++ b/arch/arm/mach-mstar/Kconfig @@ -3,6 +3,7 @@ menuconfig ARCH_MSTARV7 depends on ARCH_MULTI_V7 select ARM_GIC select ARM_HEAVY_MB + select HAVE_ARM_ARCH_TIMER select MST_IRQ select MSTAR_MSC313_MPLL help diff --git a/arch/arm/mach-s3c/mach-jive.c b/arch/arm/mach-s3c/mach-jive.c index 0785638a9069..7d15b84ae217 100644 --- a/arch/arm/mach-s3c/mach-jive.c +++ b/arch/arm/mach-s3c/mach-jive.c @@ -236,11 +236,11 @@ static int __init jive_mtdset(char *options) unsigned long set; =20 if (options =3D=3D NULL || options[0] =3D=3D '\0') - return 0; + return 1; =20 if (kstrtoul(options, 10, &set)) { printk(KERN_ERR "failed to parse mtdset=3D%s\n", options); - return 0; + return 1; } =20 switch (set) { @@ -255,7 +255,7 @@ static int __init jive_mtdset(char *options) "using default.", set); } =20 - return 0; + return 1; } =20 /* parse the mtdset=3D option given to the kernel command line */ diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index d05d94d2b28b..0a83e1728f7e 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -683,6 +683,7 @@ config ARM64_ERRATUM_2051678 =20 config ARM64_ERRATUM_2077057 bool "Cortex-A510: 2077057: workaround software-step corrupting SPSR_EL2" + default y help This option adds the workaround for ARM Cortex-A510 erratum 2077057. Affected Cortex-A510 may corrupt SPSR_EL2 when the a step exception is diff --git a/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi b/arch/arm64= /boot/dts/broadcom/bcm4908/bcm4908.dtsi index 984c737fa627..6e738f2a3701 100644 --- a/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi +++ b/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi @@ -273,9 +273,9 @@ bus@ff800000 { #size-cells =3D <1>; ranges =3D <0x00 0x00 0xff800000 0x3000>; =20 - timer: timer@400 { - compatible =3D "brcm,bcm6328-timer", "syscon"; - reg =3D <0x400 0x3c>; + twd: timer-mfd@400 { + compatible =3D "brcm,bcm4908-twd", "simple-mfd", "syscon"; + reg =3D <0x400 0x4c>; }; =20 gpio0: gpio-controller@500 { @@ -330,7 +330,7 @@ reset-controller@2644 { =20 reboot { compatible =3D "syscon-reboot"; - regmap =3D <&timer>; + regmap =3D <&twd>; offset =3D <0x34>; mask =3D <1>; }; diff --git a/arch/arm64/boot/dts/broadcom/northstar2/ns2-svk.dts b/arch/arm= 64/boot/dts/broadcom/northstar2/ns2-svk.dts index ec19fbf928a1..12a4b1c03390 100644 --- a/arch/arm64/boot/dts/broadcom/northstar2/ns2-svk.dts +++ b/arch/arm64/boot/dts/broadcom/northstar2/ns2-svk.dts @@ -111,8 +111,8 @@ slic@0 { compatible =3D "silabs,si3226x"; reg =3D <0>; spi-max-frequency =3D <5000000>; - spi-cpha =3D <1>; - spi-cpol =3D <1>; + spi-cpha; + spi-cpol; pl022,hierarchy =3D <0>; pl022,interface =3D <0>; pl022,slave-tx-disable =3D <0>; @@ -135,8 +135,8 @@ at25@0 { at25,byte-len =3D <0x8000>; at25,addr-mode =3D <2>; at25,page-size =3D <64>; - spi-cpha =3D <1>; - spi-cpol =3D <1>; + spi-cpha; + spi-cpol; pl022,hierarchy =3D <0>; pl022,interface =3D <0>; pl022,slave-tx-disable =3D <0>; diff --git a/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi b/arch/arm64/= boot/dts/broadcom/northstar2/ns2.dtsi index 2cfeaf3b0a87..8c218689fef7 100644 --- a/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi +++ b/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi @@ -687,7 +687,7 @@ sata_phy1: sata-phy@1 { }; }; =20 - sata: ahci@663f2000 { + sata: sata@663f2000 { compatible =3D "brcm,iproc-ahci", "generic-ahci"; reg =3D <0x663f2000 0x1000>; dma-coherent; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/bo= ot/dts/freescale/fsl-ls1043a.dtsi index 01b01e320411..35d1939e690b 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -536,9 +536,9 @@ i2c0: i2c@2180000 { clock-names =3D "i2c"; clocks =3D <&clockgen QORIQ_CLK_PLATFORM_PLL QORIQ_CLK_PLL_DIV(1)>; - dmas =3D <&edma0 1 39>, - <&edma0 1 38>; - dma-names =3D "tx", "rx"; + dmas =3D <&edma0 1 38>, + <&edma0 1 39>; + dma-names =3D "rx", "tx"; status =3D "disabled"; }; =20 diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/bo= ot/dts/freescale/fsl-ls1046a.dtsi index 687fea6d8afa..4e7bd04d9798 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi @@ -499,9 +499,9 @@ i2c0: i2c@2180000 { interrupts =3D ; clocks =3D <&clockgen QORIQ_CLK_PLATFORM_PLL QORIQ_CLK_PLL_DIV(2)>; - dmas =3D <&edma0 1 39>, - <&edma0 1 38>; - dma-names =3D "tx", "rx"; + dmas =3D <&edma0 1 38>, + <&edma0 1 39>; + dma-names =3D "rx", "tx"; status =3D "disabled"; }; =20 diff --git a/arch/arm64/boot/dts/qcom/ipq6018.dtsi b/arch/arm64/boot/dts/qc= om/ipq6018.dtsi index 66ec5615651d..5dea37651adf 100644 --- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi @@ -748,7 +748,7 @@ dwc_0: usb@8A00000 { snps,hird-threshold =3D /bits/ 8 <0x0>; snps,dis_u2_susphy_quirk; snps,dis_u3_susphy_quirk; - snps,ref-clock-period-ns =3D <0x32>; + snps,ref-clock-period-ns =3D <0x29>; dr_mode =3D "host"; }; }; diff --git a/arch/arm64/boot/dts/qcom/msm8994.dtsi b/arch/arm64/boot/dts/qc= om/msm8994.dtsi index 5a9a5ed0565f..215f56daa26c 100644 --- a/arch/arm64/boot/dts/qcom/msm8994.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8994.dtsi @@ -713,6 +713,9 @@ gcc: clock-controller@fc400000 { #reset-cells =3D <1>; #power-domain-cells =3D <1>; reg =3D <0xfc400000 0x2000>; + + clock-names =3D "xo", "sleep_clk"; + clocks =3D <&xo_board>, <&sleep_clk>; }; =20 rpm_msg_ram: sram@fc428000 { diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qco= m/sc7280.dtsi index 6e27a1beaa33..68a5740bc360 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -1785,7 +1785,7 @@ opp-550000000 { }; }; =20 - gmu: gmu@3d69000 { + gmu: gmu@3d6a000 { compatible=3D"qcom,adreno-gmu-635.0", "qcom,adreno-gmu"; reg =3D <0 0x03d6a000 0 0x34000>, <0 0x3de0000 0 0x10000>, diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qco= m/sdm845.dtsi index 526087586ba4..0dda3a378158 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -3613,10 +3613,10 @@ wcd9340: codec@1{ #clock-cells =3D <0>; clock-frequency =3D <9600000>; clock-output-names =3D "mclk"; - qcom,micbias1-millivolt =3D <1800>; - qcom,micbias2-millivolt =3D <1800>; - qcom,micbias3-millivolt =3D <1800>; - qcom,micbias4-millivolt =3D <1800>; + qcom,micbias1-microvolt =3D <1800000>; + qcom,micbias2-microvolt =3D <1800000>; + qcom,micbias3-microvolt =3D <1800000>; + qcom,micbias4-microvolt =3D <1800000>; =20 #address-cells =3D <1>; #size-cells =3D <1>; diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qco= m/sm8150.dtsi index 81b4ff2cc4cd..37f758cc4cc7 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -3557,9 +3557,9 @@ apps_rsc: rsc@18200000 { qcom,tcs-offset =3D <0xd00>; qcom,drv-id =3D <2>; qcom,tcs-config =3D , - , - , - ; + , + , + ; =20 rpmhcc: clock-controller { compatible =3D "qcom,sm8150-rpmh-clk"; diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qco= m/sm8250.dtsi index 6f6129b39c9c..7d1ec0432020 100644 --- a/arch/arm64/boot/dts/qcom/sm8250.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi @@ -1426,8 +1426,8 @@ pcie0: pci@1c00000 { phys =3D <&pcie0_lane>; phy-names =3D "pciephy"; =20 - perst-gpio =3D <&tlmm 79 GPIO_ACTIVE_LOW>; - enable-gpio =3D <&tlmm 81 GPIO_ACTIVE_HIGH>; + perst-gpios =3D <&tlmm 79 GPIO_ACTIVE_LOW>; + wake-gpios =3D <&tlmm 81 GPIO_ACTIVE_HIGH>; =20 pinctrl-names =3D "default"; pinctrl-0 =3D <&pcie0_default_state>; @@ -1487,7 +1487,7 @@ pcie1: pci@1c08000 { ranges =3D <0x01000000 0x0 0x40200000 0x0 0x40200000 0x0 0x100000>, <0x02000000 0x0 0x40300000 0x0 0x40300000 0x0 0x1fd00000>; =20 - interrupts =3D ; + interrupts =3D ; interrupt-names =3D "msi"; #interrupt-cells =3D <1>; interrupt-map-mask =3D <0 0 0 0x7>; @@ -1530,8 +1530,8 @@ pcie1: pci@1c08000 { phys =3D <&pcie1_lane>; phy-names =3D "pciephy"; =20 - perst-gpio =3D <&tlmm 82 GPIO_ACTIVE_LOW>; - enable-gpio =3D <&tlmm 84 GPIO_ACTIVE_HIGH>; + perst-gpios =3D <&tlmm 82 GPIO_ACTIVE_LOW>; + wake-gpios =3D <&tlmm 84 GPIO_ACTIVE_HIGH>; =20 pinctrl-names =3D "default"; pinctrl-0 =3D <&pcie1_default_state>; @@ -1593,7 +1593,7 @@ pcie2: pci@1c10000 { ranges =3D <0x01000000 0x0 0x64200000 0x0 0x64200000 0x0 0x100000>, <0x02000000 0x0 0x64300000 0x0 0x64300000 0x0 0x3d00000>; =20 - interrupts =3D ; + interrupts =3D ; interrupt-names =3D "msi"; #interrupt-cells =3D <1>; interrupt-map-mask =3D <0 0 0 0x7>; @@ -1636,8 +1636,8 @@ pcie2: pci@1c10000 { phys =3D <&pcie2_lane>; phy-names =3D "pciephy"; =20 - perst-gpio =3D <&tlmm 85 GPIO_ACTIVE_LOW>; - enable-gpio =3D <&tlmm 87 GPIO_ACTIVE_HIGH>; + perst-gpios =3D <&tlmm 85 GPIO_ACTIVE_LOW>; + wake-gpios =3D <&tlmm 87 GPIO_ACTIVE_HIGH>; =20 pinctrl-names =3D "default"; pinctrl-0 =3D <&pcie2_default_state>; diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qco= m/sm8350.dtsi index 1a70a70ed056..7c798c966755 100644 --- a/arch/arm64/boot/dts/qcom/sm8350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi @@ -1124,7 +1124,7 @@ apps_rsc: rsc@18200000 { qcom,tcs-offset =3D <0xd00>; qcom,drv-id =3D <2>; qcom,tcs-config =3D , , - , ; + , ; =20 rpmhcc: clock-controller { compatible =3D "qcom,sm8350-rpmh-clk"; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts b/arch/arm64/b= oot/dts/rockchip/rk3399-firefly.dts index c4dd2a6b4836..f81ce3240342 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts @@ -770,8 +770,8 @@ &sdio0 { sd-uhs-sdr104; =20 /* Power supply */ - vqmmc-supply =3D &vcc1v8_s3; /* IO line */ - vmmc-supply =3D &vcc_sdio; /* card's power */ + vqmmc-supply =3D <&vcc1v8_s3>; /* IO line */ + vmmc-supply =3D <&vcc_sdio>; /* card's power */ =20 #address-cells =3D <1>; #size-cells =3D <0>; diff --git a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi b/arch/arm64/boot/dts= /ti/k3-am64-main.dtsi index 5ad638b95ffc..656b279b41da 100644 --- a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi @@ -59,7 +59,10 @@ gic500: interrupt-controller@1800000 { #interrupt-cells =3D <3>; interrupt-controller; reg =3D <0x00 0x01800000 0x00 0x10000>, /* GICD */ - <0x00 0x01840000 0x00 0xC0000>; /* GICR */ + <0x00 0x01840000 0x00 0xC0000>, /* GICR */ + <0x01 0x00000000 0x00 0x2000>, /* GICC */ + <0x01 0x00010000 0x00 0x1000>, /* GICH */ + <0x01 0x00020000 0x00 0x2000>; /* GICV */ /* * vcpumntirq: * virtual CPU interface maintenance interrupt diff --git a/arch/arm64/boot/dts/ti/k3-am64.dtsi b/arch/arm64/boot/dts/ti/k= 3-am64.dtsi index 120974726be8..19684865d0d6 100644 --- a/arch/arm64/boot/dts/ti/k3-am64.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am64.dtsi @@ -87,6 +87,7 @@ cbass_main: bus@f4000 { <0x00 0x68000000 0x00 0x68000000 0x00 0x08000000>, /* PCIe DAT0 */ <0x00 0x70000000 0x00 0x70000000 0x00 0x00200000>, /* OC SRAM */ <0x00 0x78000000 0x00 0x78000000 0x00 0x00800000>, /* Main R5FSS */ + <0x01 0x00000000 0x01 0x00000000 0x00 0x00310000>, /* A53 PERIPHBASE */ <0x06 0x00000000 0x06 0x00000000 0x01 0x00000000>, /* PCIe DAT1 */ <0x05 0x00000000 0x05 0x00000000 0x01 0x00000000>, /* FSS0 DAT3 */ =20 diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts= /ti/k3-am65-main.dtsi index ce8bb4a61011..e749343acced 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi @@ -35,7 +35,10 @@ gic500: interrupt-controller@1800000 { #interrupt-cells =3D <3>; interrupt-controller; reg =3D <0x00 0x01800000 0x00 0x10000>, /* GICD */ - <0x00 0x01880000 0x00 0x90000>; /* GICR */ + <0x00 0x01880000 0x00 0x90000>, /* GICR */ + <0x00 0x6f000000 0x00 0x2000>, /* GICC */ + <0x00 0x6f010000 0x00 0x1000>, /* GICH */ + <0x00 0x6f020000 0x00 0x2000>; /* GICV */ /* * vcpumntirq: * virtual CPU interface maintenance interrupt diff --git a/arch/arm64/boot/dts/ti/k3-am65.dtsi b/arch/arm64/boot/dts/ti/k= 3-am65.dtsi index a58a39fa42db..c538a0bf3cdd 100644 --- a/arch/arm64/boot/dts/ti/k3-am65.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65.dtsi @@ -86,6 +86,7 @@ cbass_main: bus@100000 { <0x00 0x46000000 0x00 0x46000000 0x00 0x00200000>, <0x00 0x47000000 0x00 0x47000000 0x00 0x00068400>, <0x00 0x50000000 0x00 0x50000000 0x00 0x8000000>, + <0x00 0x6f000000 0x00 0x6f000000 0x00 0x00310000>, /* A53 PERIPHBASE */ <0x00 0x70000000 0x00 0x70000000 0x00 0x200000>, <0x05 0x00000000 0x05 0x00000000 0x01 0x0000000>, <0x07 0x00000000 0x07 0x00000000 0x01 0x0000000>; diff --git a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi b/arch/arm64/boot/dt= s/ti/k3-j7200-main.dtsi index 05a627ad6cdc..16684a2f054d 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi @@ -54,7 +54,10 @@ gic500: interrupt-controller@1800000 { #interrupt-cells =3D <3>; interrupt-controller; reg =3D <0x00 0x01800000 0x00 0x10000>, /* GICD */ - <0x00 0x01900000 0x00 0x100000>; /* GICR */ + <0x00 0x01900000 0x00 0x100000>, /* GICR */ + <0x00 0x6f000000 0x00 0x2000>, /* GICC */ + <0x00 0x6f010000 0x00 0x1000>, /* GICH */ + <0x00 0x6f020000 0x00 0x2000>; /* GICV */ =20 /* vcpumntirq: virtual CPU interface maintenance interrupt */ interrupts =3D ; diff --git a/arch/arm64/boot/dts/ti/k3-j7200.dtsi b/arch/arm64/boot/dts/ti/= k3-j7200.dtsi index 64fef4e67d76..b6da0454cc5b 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j7200.dtsi @@ -129,6 +129,7 @@ cbass_main: bus@100000 { <0x00 0x00a40000 0x00 0x00a40000 0x00 0x00000800>, /* timesync router = */ <0x00 0x01000000 0x00 0x01000000 0x00 0x0d000000>, /* Most peripherals= */ <0x00 0x30000000 0x00 0x30000000 0x00 0x0c400000>, /* MAIN NAVSS */ + <0x00 0x6f000000 0x00 0x6f000000 0x00 0x00310000>, /* A72 PERIPHBASE */ <0x00 0x70000000 0x00 0x70000000 0x00 0x00800000>, /* MSMC RAM */ <0x00 0x18000000 0x00 0x18000000 0x00 0x08000000>, /* PCIe1 DAT0 */ <0x41 0x00000000 0x41 0x00000000 0x01 0x00000000>, /* PCIe1 DAT1 */ diff --git a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi b/arch/arm64/boot/dt= s/ti/k3-j721e-main.dtsi index e85c89eebfa3..6c81997ee28a 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi @@ -76,7 +76,10 @@ gic500: interrupt-controller@1800000 { #interrupt-cells =3D <3>; interrupt-controller; reg =3D <0x00 0x01800000 0x00 0x10000>, /* GICD */ - <0x00 0x01900000 0x00 0x100000>; /* GICR */ + <0x00 0x01900000 0x00 0x100000>, /* GICR */ + <0x00 0x6f000000 0x00 0x2000>, /* GICC */ + <0x00 0x6f010000 0x00 0x1000>, /* GICH */ + <0x00 0x6f020000 0x00 0x2000>; /* GICV */ =20 /* vcpumntirq: virtual CPU interface maintenance interrupt */ interrupts =3D ; diff --git a/arch/arm64/boot/dts/ti/k3-j721e.dtsi b/arch/arm64/boot/dts/ti/= k3-j721e.dtsi index 4a3872fce533..0e23886c9fd1 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721e.dtsi @@ -139,6 +139,7 @@ cbass_main: bus@100000 { <0x00 0x0e000000 0x00 0x0e000000 0x00 0x01800000>, /* PCIe Core*/ <0x00 0x10000000 0x00 0x10000000 0x00 0x10000000>, /* PCIe DAT */ <0x00 0x64800000 0x00 0x64800000 0x00 0x00800000>, /* C71 */ + <0x00 0x6f000000 0x00 0x6f000000 0x00 0x00310000>, /* A72 PERIPHBASE */ <0x44 0x00000000 0x44 0x00000000 0x00 0x08000000>, /* PCIe2 DAT */ <0x44 0x10000000 0x44 0x10000000 0x00 0x08000000>, /* PCIe3 DAT */ <0x4d 0x80800000 0x4d 0x80800000 0x00 0x00800000>, /* C66_0 */ diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index f2e2b9bdd702..d1fdf68be26e 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -931,7 +931,7 @@ CONFIG_DMADEVICES=3Dy CONFIG_DMA_BCM2835=3Dy CONFIG_DMA_SUN6I=3Dm CONFIG_FSL_EDMA=3Dy -CONFIG_IMX_SDMA=3Dy +CONFIG_IMX_SDMA=3Dm CONFIG_K3_DMA=3Dy CONFIG_MV_XOR=3Dy CONFIG_MV_XOR_V2=3Dy diff --git a/arch/arm64/include/asm/module.lds.h b/arch/arm64/include/asm/m= odule.lds.h index a11ccadd47d2..094701ec5500 100644 --- a/arch/arm64/include/asm/module.lds.h +++ b/arch/arm64/include/asm/module.lds.h @@ -1,8 +1,8 @@ SECTIONS { #ifdef CONFIG_ARM64_MODULE_PLTS - .plt 0 (NOLOAD) : { BYTE(0) } - .init.plt 0 (NOLOAD) : { BYTE(0) } - .text.ftrace_trampoline 0 (NOLOAD) : { BYTE(0) } + .plt 0 : { BYTE(0) } + .init.plt 0 : { BYTE(0) } + .text.ftrace_trampoline 0 : { BYTE(0) } #endif =20 #ifdef CONFIG_KASAN_SW_TAGS diff --git a/arch/arm64/include/asm/spectre.h b/arch/arm64/include/asm/spec= tre.h index 86e0cc9b9c68..aa3d3607d5c8 100644 --- a/arch/arm64/include/asm/spectre.h +++ b/arch/arm64/include/asm/spectre.h @@ -67,7 +67,8 @@ struct bp_hardening_data { =20 DECLARE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data); =20 -static inline void arm64_apply_bp_hardening(void) +/* Called during entry so must be __always_inline */ +static __always_inline void arm64_apply_bp_hardening(void) { struct bp_hardening_data *d; =20 diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pac= k.c index 6d45c63c6454..5777929d35bf 100644 --- a/arch/arm64/kernel/proton-pack.c +++ b/arch/arm64/kernel/proton-pack.c @@ -233,17 +233,20 @@ static void install_bp_hardening_cb(bp_hardening_cb_t= fn) __this_cpu_write(bp_hardening_data.slot, HYP_VECTOR_SPECTRE_DIRECT); } =20 -static void call_smc_arch_workaround_1(void) +/* Called during entry so must be noinstr */ +static noinstr void call_smc_arch_workaround_1(void) { arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL); } =20 -static void call_hvc_arch_workaround_1(void) +/* Called during entry so must be noinstr */ +static noinstr void call_hvc_arch_workaround_1(void) { arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL); } =20 -static void qcom_link_stack_sanitisation(void) +/* Called during entry so must be noinstr */ +static noinstr void qcom_link_stack_sanitisation(void) { u64 tmp; =20 diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index 8f6372b44b65..da5de3d27f11 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c @@ -577,10 +577,12 @@ static int setup_sigframe_layout(struct rt_sigframe_u= ser_layout *user, { int err; =20 - err =3D sigframe_alloc(user, &user->fpsimd_offset, - sizeof(struct fpsimd_context)); - if (err) - return err; + if (system_supports_fpsimd()) { + err =3D sigframe_alloc(user, &user->fpsimd_offset, + sizeof(struct fpsimd_context)); + if (err) + return err; + } =20 /* fault information, if valid */ if (add_all || current->thread.fault_code) { diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index a8834434af99..2d9cac6df29e 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -61,8 +61,34 @@ EXPORT_SYMBOL(memstart_addr); * unless restricted on specific platforms (e.g. 30-bit on Raspberry Pi 4). * In such case, ZONE_DMA32 covers the rest of the 32-bit addressable memo= ry, * otherwise it is empty. + * + * Memory reservation for crash kernel either done early or deferred + * depending on DMA memory zones configs (ZONE_DMA) -- + * + * In absence of ZONE_DMA configs arm64_dma_phys_limit initialized + * here instead of max_zone_phys(). This lets early reservation of + * crash kernel memory which has a dependency on arm64_dma_phys_limit. + * Reserving memory early for crash kernel allows linear creation of block + * mappings (greater than page-granularity) for all the memory bank rangs. + * In this scheme a comparatively quicker boot is observed. + * + * If ZONE_DMA configs are defined, crash kernel memory reservation + * is delayed until DMA zone memory range size initilazation performed in + * zone_sizes_init(). The defer is necessary to steer clear of DMA zone + * memory range to avoid overlap allocation. So crash kernel memory bound= aries + * are not known when mapping all bank memory ranges, which otherwise means + * not possible to exclude crash kernel range from creating block mappings + * so page-granularity mappings are created for the entire memory range. + * Hence a slightly slower boot is observed. + * + * Note: Page-granularity mapppings are necessary for crash kernel memory + * range for shrinking its size via /sys/kernel/kexec_crash_size interface. */ -phys_addr_t arm64_dma_phys_limit __ro_after_init; +#if IS_ENABLED(CONFIG_ZONE_DMA) || IS_ENABLED(CONFIG_ZONE_DMA32) +phys_addr_t __ro_after_init arm64_dma_phys_limit; +#else +phys_addr_t __ro_after_init arm64_dma_phys_limit =3D PHYS_MASK + 1; +#endif =20 #ifdef CONFIG_KEXEC_CORE /* @@ -153,8 +179,6 @@ static void __init zone_sizes_init(unsigned long min, u= nsigned long max) if (!arm64_dma_phys_limit) arm64_dma_phys_limit =3D dma32_phys_limit; #endif - if (!arm64_dma_phys_limit) - arm64_dma_phys_limit =3D PHYS_MASK + 1; max_zone_pfns[ZONE_NORMAL] =3D max; =20 free_area_init(max_zone_pfns); @@ -315,6 +339,9 @@ void __init arm64_memblock_init(void) =20 early_init_fdt_scan_reserved_mem(); =20 + if (!IS_ENABLED(CONFIG_ZONE_DMA) && !IS_ENABLED(CONFIG_ZONE_DMA32)) + reserve_crashkernel(); + high_memory =3D __va(memblock_end_of_DRAM() - 1) + 1; } =20 @@ -361,7 +388,8 @@ void __init bootmem_init(void) * request_standard_resources() depends on crashkernel's memory being * reserved, so do it here. */ - reserve_crashkernel(); + if (IS_ENABLED(CONFIG_ZONE_DMA) || IS_ENABLED(CONFIG_ZONE_DMA32)) + reserve_crashkernel(); =20 memblock_dump_all(); } diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 49abbf43bf35..37b8230cda6a 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -63,6 +63,7 @@ static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss __ma= ybe_unused; static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss __maybe_unused; =20 static DEFINE_SPINLOCK(swapper_pgdir_lock); +static DEFINE_MUTEX(fixmap_lock); =20 void set_swapper_pgd(pgd_t *pgdp, pgd_t pgd) { @@ -329,6 +330,12 @@ static void alloc_init_pud(pgd_t *pgdp, unsigned long = addr, unsigned long end, } BUG_ON(p4d_bad(p4d)); =20 + /* + * No need for locking during early boot. And it doesn't work as + * expected with KASLR enabled. + */ + if (system_state !=3D SYSTEM_BOOTING) + mutex_lock(&fixmap_lock); pudp =3D pud_set_fixmap_offset(p4dp, addr); do { pud_t old_pud =3D READ_ONCE(*pudp); @@ -359,6 +366,8 @@ static void alloc_init_pud(pgd_t *pgdp, unsigned long a= ddr, unsigned long end, } while (pudp++, addr =3D next, addr !=3D end); =20 pud_clear_fixmap(); + if (system_state !=3D SYSTEM_BOOTING) + mutex_unlock(&fixmap_lock); } =20 static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys, @@ -517,7 +526,7 @@ static void __init map_mem(pgd_t *pgdp) */ BUILD_BUG_ON(pgd_index(direct_map_end - 1) =3D=3D pgd_index(direct_map_en= d)); =20 - if (can_set_direct_map() || crash_mem_map || IS_ENABLED(CONFIG_KFENCE)) + if (can_set_direct_map() || IS_ENABLED(CONFIG_KFENCE)) flags |=3D NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; =20 /* @@ -528,6 +537,17 @@ static void __init map_mem(pgd_t *pgdp) */ memblock_mark_nomap(kernel_start, kernel_end - kernel_start); =20 +#ifdef CONFIG_KEXEC_CORE + if (crash_mem_map) { + if (IS_ENABLED(CONFIG_ZONE_DMA) || + IS_ENABLED(CONFIG_ZONE_DMA32)) + flags |=3D NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; + else if (crashk_res.end) + memblock_mark_nomap(crashk_res.start, + resource_size(&crashk_res)); + } +#endif + /* map all the memory banks */ for_each_mem_range(i, &start, &end) { if (start >=3D end) @@ -554,6 +574,25 @@ static void __init map_mem(pgd_t *pgdp) __map_memblock(pgdp, kernel_start, kernel_end, PAGE_KERNEL, NO_CONT_MAPPINGS); memblock_clear_nomap(kernel_start, kernel_end - kernel_start); + + /* + * Use page-level mappings here so that we can shrink the region + * in page granularity and put back unused memory to buddy system + * through /sys/kernel/kexec_crash_size interface. + */ +#ifdef CONFIG_KEXEC_CORE + if (crash_mem_map && + !IS_ENABLED(CONFIG_ZONE_DMA) && !IS_ENABLED(CONFIG_ZONE_DMA32)) { + if (crashk_res.end) { + __map_memblock(pgdp, crashk_res.start, + crashk_res.end + 1, + PAGE_KERNEL, + NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS); + memblock_clear_nomap(crashk_res.start, + resource_size(&crashk_res)); + } + } +#endif } =20 void mark_rodata_ro(void) diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index 71ef9dcd9b57..4d4e6ae39e56 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -1049,15 +1049,18 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_pro= g *prog) goto out_off; } =20 - /* 1. Initial fake pass to compute ctx->idx. */ - - /* Fake pass to fill in ctx->offset. */ - if (build_body(&ctx, extra_pass)) { + /* + * 1. Initial fake pass to compute ctx->idx and ctx->offset. + * + * BPF line info needs ctx->offset[i] to be the offset of + * instruction[i] in jited image, so build prologue first. + */ + if (build_prologue(&ctx, was_classic)) { prog =3D orig_prog; goto out_off; } =20 - if (build_prologue(&ctx, was_classic)) { + if (build_body(&ctx, extra_pass)) { prog =3D orig_prog; goto out_off; } @@ -1130,6 +1133,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog= *prog) prog->jited_len =3D prog_size; =20 if (!prog->is_func || extra_pass) { + int i; + + /* offset[prog->len] is the size of program */ + for (i =3D 0; i <=3D prog->len; i++) + ctx.offset[i] *=3D AARCH64_INSN_SIZE; bpf_prog_fill_jited_linfo(prog, ctx.offset + 1); out_off: kfree(ctx.offset); diff --git a/arch/csky/kernel/perf_callchain.c b/arch/csky/kernel/perf_call= chain.c index 35318a635a5f..75e1f9df5f60 100644 --- a/arch/csky/kernel/perf_callchain.c +++ b/arch/csky/kernel/perf_callchain.c @@ -49,7 +49,7 @@ static unsigned long user_backtrace(struct perf_callchain= _entry_ctx *entry, { struct stackframe buftail; unsigned long lr =3D 0; - unsigned long *user_frame_tail =3D (unsigned long *)fp; + unsigned long __user *user_frame_tail =3D (unsigned long __user *)fp; =20 /* Check accessibility of one struct frame_tail beyond */ if (!access_ok(user_frame_tail, sizeof(buftail))) diff --git a/arch/csky/kernel/signal.c b/arch/csky/kernel/signal.c index c7b763d2f526..8867ddf3e6c7 100644 --- a/arch/csky/kernel/signal.c +++ b/arch/csky/kernel/signal.c @@ -136,7 +136,7 @@ static inline void __user *get_sigframe(struct ksignal = *ksig, static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) { - struct rt_sigframe *frame; + struct rt_sigframe __user *frame; int err =3D 0; =20 frame =3D get_sigframe(ksig, regs, sizeof(*frame)); diff --git a/arch/m68k/coldfire/device.c b/arch/m68k/coldfire/device.c index 0386252e9d04..4218750414bb 100644 --- a/arch/m68k/coldfire/device.c +++ b/arch/m68k/coldfire/device.c @@ -480,7 +480,7 @@ static struct platform_device mcf_i2c5 =3D { #endif /* MCFI2C_BASE5 */ #endif /* IS_ENABLED(CONFIG_I2C_IMX) */ =20 -#if IS_ENABLED(CONFIG_MCF_EDMA) +#ifdef MCFEDMA_BASE =20 static const struct dma_slave_map mcf_edma_map[] =3D { { "dreq0", "rx-tx", MCF_EDMA_FILTER_PARAM(0) }, @@ -552,7 +552,7 @@ static struct platform_device mcf_edma =3D { .platform_data =3D &mcf_edma_data, } }; -#endif /* IS_ENABLED(CONFIG_MCF_EDMA) */ +#endif /* MCFEDMA_BASE */ =20 #ifdef MCFSDHC_BASE static struct mcf_esdhc_platform_data mcf_esdhc_data =3D { @@ -651,7 +651,7 @@ static struct platform_device *mcf_devices[] __initdata= =3D { &mcf_i2c5, #endif #endif -#if IS_ENABLED(CONFIG_MCF_EDMA) +#ifdef MCFEDMA_BASE &mcf_edma, #endif #ifdef MCFSDHC_BASE diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/includ= e/asm/uaccess.h index 5b6e0e7788f4..3fe96979d2c6 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -130,27 +130,27 @@ extern long __user_bad(void); =20 #define __get_user(x, ptr) \ ({ \ - unsigned long __gu_val =3D 0; \ long __gu_err; \ switch (sizeof(*(ptr))) { \ case 1: \ - __get_user_asm("lbu", (ptr), __gu_val, __gu_err); \ + __get_user_asm("lbu", (ptr), x, __gu_err); \ break; \ case 2: \ - __get_user_asm("lhu", (ptr), __gu_val, __gu_err); \ + __get_user_asm("lhu", (ptr), x, __gu_err); \ break; \ case 4: \ - __get_user_asm("lw", (ptr), __gu_val, __gu_err); \ + __get_user_asm("lw", (ptr), x, __gu_err); \ break; \ - case 8: \ - __gu_err =3D __copy_from_user(&__gu_val, ptr, 8); \ - if (__gu_err) \ - __gu_err =3D -EFAULT; \ + case 8: { \ + __u64 __x =3D 0; \ + __gu_err =3D raw_copy_from_user(&__x, ptr, 8) ? \ + -EFAULT : 0; \ + (x) =3D (typeof(x))(typeof((x) - (x)))__x; \ break; \ + } \ default: \ /* __gu_val =3D 0; __gu_err =3D -EINVAL;*/ __gu_err =3D __user_bad();\ } \ - x =3D (__force __typeof__(*(ptr))) __gu_val; \ __gu_err; \ }) =20 diff --git a/arch/mips/crypto/crc32-mips.c b/arch/mips/crypto/crc32-mips.c index 0a03529cf317..3e4f5ba104f8 100644 --- a/arch/mips/crypto/crc32-mips.c +++ b/arch/mips/crypto/crc32-mips.c @@ -28,7 +28,7 @@ enum crc_type { }; =20 #ifndef TOOLCHAIN_SUPPORTS_CRC -#define _ASM_MACRO_CRC32(OP, SZ, TYPE) \ +#define _ASM_SET_CRC(OP, SZ, TYPE) \ _ASM_MACRO_3R(OP, rt, rs, rt2, \ ".ifnc \\rt, \\rt2\n\t" \ ".error \"invalid operands \\\"" #OP " \\rt,\\rs,\\rt2\\\"\"\n\t" \ @@ -37,30 +37,36 @@ _ASM_MACRO_3R(OP, rt, rs, rt2, \ ((SZ) << 6) | ((TYPE) << 8)) \ _ASM_INSN32_IF_MM(0x00000030 | (__rs << 16) | (__rt << 21) | \ ((SZ) << 14) | ((TYPE) << 3))) -_ASM_MACRO_CRC32(crc32b, 0, 0); -_ASM_MACRO_CRC32(crc32h, 1, 0); -_ASM_MACRO_CRC32(crc32w, 2, 0); -_ASM_MACRO_CRC32(crc32d, 3, 0); -_ASM_MACRO_CRC32(crc32cb, 0, 1); -_ASM_MACRO_CRC32(crc32ch, 1, 1); -_ASM_MACRO_CRC32(crc32cw, 2, 1); -_ASM_MACRO_CRC32(crc32cd, 3, 1); -#define _ASM_SET_CRC "" +#define _ASM_UNSET_CRC(op, SZ, TYPE) ".purgem " #op "\n\t" #else /* !TOOLCHAIN_SUPPORTS_CRC */ -#define _ASM_SET_CRC ".set\tcrc\n\t" +#define _ASM_SET_CRC(op, SZ, TYPE) ".set\tcrc\n\t" +#define _ASM_UNSET_CRC(op, SZ, TYPE) #endif =20 -#define _CRC32(crc, value, size, type) \ -do { \ - __asm__ __volatile__( \ - ".set push\n\t" \ - _ASM_SET_CRC \ - #type #size " %0, %1, %0\n\t" \ - ".set pop" \ - : "+r" (crc) \ - : "r" (value)); \ +#define __CRC32(crc, value, op, SZ, TYPE) \ +do { \ + __asm__ __volatile__( \ + ".set push\n\t" \ + _ASM_SET_CRC(op, SZ, TYPE) \ + #op " %0, %1, %0\n\t" \ + _ASM_UNSET_CRC(op, SZ, TYPE) \ + ".set pop" \ + : "+r" (crc) \ + : "r" (value)); \ } while (0) =20 +#define _CRC32_crc32b(crc, value) __CRC32(crc, value, crc32b, 0, 0) +#define _CRC32_crc32h(crc, value) __CRC32(crc, value, crc32h, 1, 0) +#define _CRC32_crc32w(crc, value) __CRC32(crc, value, crc32w, 2, 0) +#define _CRC32_crc32d(crc, value) __CRC32(crc, value, crc32d, 3, 0) +#define _CRC32_crc32cb(crc, value) __CRC32(crc, value, crc32cb, 0, 1) +#define _CRC32_crc32ch(crc, value) __CRC32(crc, value, crc32ch, 1, 1) +#define _CRC32_crc32cw(crc, value) __CRC32(crc, value, crc32cw, 2, 1) +#define _CRC32_crc32cd(crc, value) __CRC32(crc, value, crc32cd, 3, 1) + +#define _CRC32(crc, value, size, op) \ + _CRC32_##op##size(crc, value) + #define CRC32(crc, value, size) \ _CRC32(crc, value, size, crc32) =20 diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S index ea5b5a83f1e1..011d1d678840 100644 --- a/arch/mips/dec/int-handler.S +++ b/arch/mips/dec/int-handler.S @@ -131,7 +131,7 @@ */ mfc0 t0,CP0_CAUSE # get pending interrupts mfc0 t1,CP0_STATUS -#ifdef CONFIG_32BIT +#if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT) lw t2,cpu_fpu_mask #endif andi t0,ST0_IM # CAUSE.CE may be non-zero! @@ -139,7 +139,7 @@ =20 beqz t0,spurious =20 -#ifdef CONFIG_32BIT +#if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT) and t2,t0 bnez t2,fpu # handle FPU immediately #endif @@ -280,7 +280,7 @@ handle_it: j dec_irq_dispatch nop =20 -#ifdef CONFIG_32BIT +#if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT) fpu: lw t0,fpu_kstat_irq nop diff --git a/arch/mips/dec/prom/Makefile b/arch/mips/dec/prom/Makefile index d95016016b42..2bad87551203 100644 --- a/arch/mips/dec/prom/Makefile +++ b/arch/mips/dec/prom/Makefile @@ -6,4 +6,4 @@ =20 lib-y +=3D init.o memory.o cmdline.o identify.o console.o =20 -lib-$(CONFIG_32BIT) +=3D locore.o +lib-$(CONFIG_CPU_R3000) +=3D locore.o diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c index a8a30bb1dee8..82b00e45ce50 100644 --- a/arch/mips/dec/setup.c +++ b/arch/mips/dec/setup.c @@ -746,7 +746,8 @@ void __init arch_init_irq(void) dec_interrupt[DEC_IRQ_HALT] =3D -1; =20 /* Register board interrupts: FPU and cascade. */ - if (dec_interrupt[DEC_IRQ_FPU] >=3D 0 && cpu_has_fpu) { + if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT) && + dec_interrupt[DEC_IRQ_FPU] >=3D 0 && cpu_has_fpu) { struct irq_desc *desc_fpu; int irq_fpu; =20 diff --git a/arch/mips/include/asm/dec/prom.h b/arch/mips/include/asm/dec/p= rom.h index 62c7dfb90e06..1e1247add1cf 100644 --- a/arch/mips/include/asm/dec/prom.h +++ b/arch/mips/include/asm/dec/prom.h @@ -43,16 +43,11 @@ */ #define REX_PROM_MAGIC 0x30464354 =20 -#ifdef CONFIG_64BIT - -#define prom_is_rex(magic) 1 /* KN04 and KN05 are REX PROMs. */ - -#else /* !CONFIG_64BIT */ - -#define prom_is_rex(magic) ((magic) =3D=3D REX_PROM_MAGIC) - -#endif /* !CONFIG_64BIT */ - +/* KN04 and KN05 are REX PROMs, so only do the check for R3k systems. */ +static inline bool prom_is_rex(u32 magic) +{ + return !IS_ENABLED(CONFIG_CPU_R3000) || magic =3D=3D REX_PROM_MAGIC; +} =20 /* * 3MIN/MAXINE PROM entry points for DS5000/1xx's, DS5000/xx's and diff --git a/arch/mips/include/asm/pgalloc.h b/arch/mips/include/asm/pgallo= c.h index c7925d0e9874..867e9c3db76e 100644 --- a/arch/mips/include/asm/pgalloc.h +++ b/arch/mips/include/asm/pgalloc.h @@ -15,6 +15,7 @@ =20 #define __HAVE_ARCH_PMD_ALLOC_ONE #define __HAVE_ARCH_PUD_ALLOC_ONE +#define __HAVE_ARCH_PGD_FREE #include =20 static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, @@ -48,6 +49,11 @@ static inline void pud_populate(struct mm_struct *mm, pu= d_t *pud, pmd_t *pmd) extern void pgd_init(unsigned long page); extern pgd_t *pgd_alloc(struct mm_struct *mm); =20 +static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) +{ + free_pages((unsigned long)pgd, PGD_ORDER); +} + #define __pte_free_tlb(tlb,pte,address) \ do { \ pgtable_pte_page_dtor(pte); \ diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index b131e6a77383..5cda07688f67 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -2160,16 +2160,14 @@ static void build_r4000_tlb_load_handler(void) uasm_i_tlbr(&p); =20 switch (current_cpu_type()) { - default: - if (cpu_has_mips_r2_exec_hazard) { - uasm_i_ehb(&p); - fallthrough; - case CPU_CAVIUM_OCTEON: case CPU_CAVIUM_OCTEON_PLUS: case CPU_CAVIUM_OCTEON2: - break; - } + break; + default: + if (cpu_has_mips_r2_exec_hazard) + uasm_i_ehb(&p); + break; } =20 /* Examine entrylo 0 or 1 based on ptr. */ @@ -2236,15 +2234,14 @@ static void build_r4000_tlb_load_handler(void) uasm_i_tlbr(&p); =20 switch (current_cpu_type()) { - default: - if (cpu_has_mips_r2_exec_hazard) { - uasm_i_ehb(&p); - case CPU_CAVIUM_OCTEON: case CPU_CAVIUM_OCTEON_PLUS: case CPU_CAVIUM_OCTEON2: - break; - } + break; + default: + if (cpu_has_mips_r2_exec_hazard) + uasm_i_ehb(&p); + break; } =20 /* Examine entrylo 0 or 1 based on ptr. */ diff --git a/arch/mips/rb532/devices.c b/arch/mips/rb532/devices.c index 04684990e28e..b7f6f782d9a1 100644 --- a/arch/mips/rb532/devices.c +++ b/arch/mips/rb532/devices.c @@ -301,11 +301,9 @@ static int __init plat_setup_devices(void) static int __init setup_kmac(char *s) { printk(KERN_INFO "korina mac =3D %s\n", s); - if (!mac_pton(s, korina_dev0_data.mac)) { + if (!mac_pton(s, korina_dev0_data.mac)) printk(KERN_ERR "Invalid mac\n"); - return -EINVAL; - } - return 0; + return 1; } =20 __setup("kmac=3D", setup_kmac); diff --git a/arch/nios2/include/asm/uaccess.h b/arch/nios2/include/asm/uacc= ess.h index ba9340e96fd4..ca9285a915ef 100644 --- a/arch/nios2/include/asm/uaccess.h +++ b/arch/nios2/include/asm/uaccess.h @@ -88,6 +88,7 @@ extern __must_check long strnlen_user(const char __user *= s, long n); /* Optimized macros */ #define __get_user_asm(val, insn, addr, err) \ { \ + unsigned long __gu_val; \ __asm__ __volatile__( \ " movi %0, %3\n" \ "1: " insn " %1, 0(%2)\n" \ @@ -96,14 +97,20 @@ extern __must_check long strnlen_user(const char __user= *s, long n); " .section __ex_table,\"a\"\n" \ " .word 1b, 2b\n" \ " .previous" \ - : "=3D&r" (err), "=3Dr" (val) \ + : "=3D&r" (err), "=3Dr" (__gu_val) \ : "r" (addr), "i" (-EFAULT)); \ + val =3D (__force __typeof__(*(addr)))__gu_val; \ } =20 -#define __get_user_unknown(val, size, ptr, err) do { \ +extern void __get_user_unknown(void); + +#define __get_user_8(val, ptr, err) do { \ + u64 __val =3D 0; \ err =3D 0; \ - if (__copy_from_user(&(val), ptr, size)) { \ + if (raw_copy_from_user(&(__val), ptr, sizeof(val))) { \ err =3D -EFAULT; \ + } else { \ + val =3D (typeof(val))(typeof((val) - (val)))__val; \ } \ } while (0) =20 @@ -119,8 +126,11 @@ do { \ case 4: \ __get_user_asm(val, "ldw", ptr, err); \ break; \ + case 8: \ + __get_user_8(val, ptr, err); \ + break; \ default: \ - __get_user_unknown(val, size, ptr, err); \ + __get_user_unknown(); \ break; \ } \ } while (0) @@ -129,9 +139,7 @@ do { \ ({ \ long __gu_err =3D -EFAULT; \ const __typeof__(*(ptr)) __user *__gu_ptr =3D (ptr); \ - unsigned long __gu_val =3D 0; \ - __get_user_common(__gu_val, sizeof(*(ptr)), __gu_ptr, __gu_err);\ - (x) =3D (__force __typeof__(x))__gu_val; \ + __get_user_common(x, sizeof(*(ptr)), __gu_ptr, __gu_err); \ __gu_err; \ }) =20 @@ -139,11 +147,9 @@ do { \ ({ \ long __gu_err =3D -EFAULT; \ const __typeof__(*(ptr)) __user *__gu_ptr =3D (ptr); \ - unsigned long __gu_val =3D 0; \ if (access_ok( __gu_ptr, sizeof(*__gu_ptr))) \ - __get_user_common(__gu_val, sizeof(*__gu_ptr), \ + __get_user_common(x, sizeof(*__gu_ptr), \ __gu_ptr, __gu_err); \ - (x) =3D (__force __typeof__(x))__gu_val; \ __gu_err; \ }) =20 diff --git a/arch/nios2/kernel/signal.c b/arch/nios2/kernel/signal.c index 2009ae2d3c3b..386e46443b60 100644 --- a/arch/nios2/kernel/signal.c +++ b/arch/nios2/kernel/signal.c @@ -36,10 +36,10 @@ struct rt_sigframe { =20 static inline int rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, - struct ucontext *uc, int *pr2) + struct ucontext __user *uc, int *pr2) { int temp; - unsigned long *gregs =3D uc->uc_mcontext.gregs; + unsigned long __user *gregs =3D uc->uc_mcontext.gregs; int err; =20 /* Always make any pending restarted system calls return -EINTR */ @@ -102,10 +102,11 @@ asmlinkage int do_rt_sigreturn(struct switch_stack *s= w) { struct pt_regs *regs =3D (struct pt_regs *)(sw + 1); /* Verify, can we follow the stack back */ - struct rt_sigframe *frame =3D (struct rt_sigframe *) regs->sp; + struct rt_sigframe __user *frame; sigset_t set; int rval; =20 + frame =3D (struct rt_sigframe __user *) regs->sp; if (!access_ok(frame, sizeof(*frame))) goto badframe; =20 @@ -124,10 +125,10 @@ asmlinkage int do_rt_sigreturn(struct switch_stack *s= w) return 0; } =20 -static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *r= egs) +static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_= regs *regs) { struct switch_stack *sw =3D (struct switch_stack *)regs - 1; - unsigned long *gregs =3D uc->uc_mcontext.gregs; + unsigned long __user *gregs =3D uc->uc_mcontext.gregs; int err =3D 0; =20 err |=3D __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); @@ -162,8 +163,9 @@ static inline int rt_setup_ucontext(struct ucontext *uc= , struct pt_regs *regs) return err; } =20 -static inline void *get_sigframe(struct ksignal *ksig, struct pt_regs *reg= s, - size_t frame_size) +static inline void __user *get_sigframe(struct ksignal *ksig, + struct pt_regs *regs, + size_t frame_size) { unsigned long usp; =20 @@ -174,13 +176,13 @@ static inline void *get_sigframe(struct ksignal *ksig= , struct pt_regs *regs, usp =3D sigsp(usp, ksig); =20 /* Verify, is it 32 or 64 bit aligned */ - return (void *)((usp - frame_size) & -8UL); + return (void __user *)((usp - frame_size) & -8UL); } =20 static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) { - struct rt_sigframe *frame; + struct rt_sigframe __user *frame; int err =3D 0; =20 frame =3D get_sigframe(ksig, regs, sizeof(*frame)); diff --git a/arch/parisc/include/asm/traps.h b/arch/parisc/include/asm/trap= s.h index 34619f010c63..0ccdb738a9a3 100644 --- a/arch/parisc/include/asm/traps.h +++ b/arch/parisc/include/asm/traps.h @@ -18,6 +18,7 @@ unsigned long parisc_acctyp(unsigned long code, unsigned = int inst); const char *trap_name(unsigned long code); void do_page_fault(struct pt_regs *regs, unsigned long code, unsigned long address); +int handle_nadtlb_fault(struct pt_regs *regs); #endif =20 #endif diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 94150b91c96f..bce71cefe572 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -558,15 +558,6 @@ static void flush_cache_pages(struct vm_area_struct *v= ma, struct mm_struct *mm, } } =20 -static void flush_user_cache_tlb(struct vm_area_struct *vma, - unsigned long start, unsigned long end) -{ - flush_user_dcache_range_asm(start, end); - if (vma->vm_flags & VM_EXEC) - flush_user_icache_range_asm(start, end); - flush_tlb_range(vma, start, end); -} - void flush_cache_mm(struct mm_struct *mm) { struct vm_area_struct *vma; @@ -581,17 +572,8 @@ void flush_cache_mm(struct mm_struct *mm) return; } =20 - preempt_disable(); - if (mm->context =3D=3D mfsp(3)) { - for (vma =3D mm->mmap; vma; vma =3D vma->vm_next) - flush_user_cache_tlb(vma, vma->vm_start, vma->vm_end); - preempt_enable(); - return; - } - for (vma =3D mm->mmap; vma; vma =3D vma->vm_next) flush_cache_pages(vma, mm, vma->vm_start, vma->vm_end); - preempt_enable(); } =20 void flush_cache_range(struct vm_area_struct *vma, @@ -605,15 +587,7 @@ void flush_cache_range(struct vm_area_struct *vma, return; } =20 - preempt_disable(); - if (vma->vm_mm->context =3D=3D mfsp(3)) { - flush_user_cache_tlb(vma, start, end); - preempt_enable(); - return; - } - - flush_cache_pages(vma, vma->vm_mm, vma->vm_start, vma->vm_end); - preempt_enable(); + flush_cache_pages(vma, vma->vm_mm, start, end); } =20 void diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index eb41fece1910..b56aab7141ed 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -662,6 +662,8 @@ void notrace handle_interruption(int code, struct pt_re= gs *regs) by hand. Technically we need to emulate: fdc,fdce,pdc,"fic,4f",prober,probeir,probew, probeiw */ + if (code =3D=3D 17 && handle_nadtlb_fault(regs)) + return; fault_address =3D regs->ior; fault_space =3D regs->isr; break; diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index 4a6221b869fd..22ffe11cec72 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -424,3 +424,92 @@ void do_page_fault(struct pt_regs *regs, unsigned long= code, goto no_context; pagefault_out_of_memory(); } + +/* Handle non-access data TLB miss faults. + * + * For probe instructions, accesses to userspace are considered allowed + * if they lie in a valid VMA and the access type matches. We are not + * allowed to handle MM faults here so there may be situations where an + * actual access would fail even though a probe was successful. + */ +int +handle_nadtlb_fault(struct pt_regs *regs) +{ + unsigned long insn =3D regs->iir; + int breg, treg, xreg, val =3D 0; + struct vm_area_struct *vma, *prev_vma; + struct task_struct *tsk; + struct mm_struct *mm; + unsigned long address; + unsigned long acc_type; + + switch (insn & 0x380) { + case 0x280: + /* FDC instruction */ + fallthrough; + case 0x380: + /* PDC and FIC instructions */ + if (printk_ratelimit()) { + pr_warn("BUG: nullifying cache flush/purge instruction\n"); + show_regs(regs); + } + if (insn & 0x20) { + /* Base modification */ + breg =3D (insn >> 21) & 0x1f; + xreg =3D (insn >> 16) & 0x1f; + if (breg && xreg) + regs->gr[breg] +=3D regs->gr[xreg]; + } + regs->gr[0] |=3D PSW_N; + return 1; + + case 0x180: + /* PROBE instruction */ + treg =3D insn & 0x1f; + if (regs->isr) { + tsk =3D current; + mm =3D tsk->mm; + if (mm) { + /* Search for VMA */ + address =3D regs->ior; + mmap_read_lock(mm); + vma =3D find_vma_prev(mm, address, &prev_vma); + mmap_read_unlock(mm); + + /* + * Check if access to the VMA is okay. + * We don't allow for stack expansion. + */ + acc_type =3D (insn & 0x40) ? VM_WRITE : VM_READ; + if (vma + && address >=3D vma->vm_start + && (vma->vm_flags & acc_type) =3D=3D acc_type) + val =3D 1; + } + } + if (treg) + regs->gr[treg] =3D val; + regs->gr[0] |=3D PSW_N; + return 1; + + case 0x300: + /* LPA instruction */ + if (insn & 0x20) { + /* Base modification */ + breg =3D (insn >> 21) & 0x1f; + xreg =3D (insn >> 16) & 0x1f; + if (breg && xreg) + regs->gr[breg] +=3D regs->gr[xreg]; + } + treg =3D insn & 0x1f; + if (treg) + regs->gr[treg] =3D 0; + regs->gr[0] |=3D PSW_N; + return 1; + + default: + break; + } + + return 0; +} diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index e02568f17334..3d2e74ebc014 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -171,7 +171,7 @@ else CFLAGS-$(CONFIG_GENERIC_CPU) +=3D $(call cc-option,-mtune=3Dpower7,$(call = cc-option,-mtune=3Dpower5)) CFLAGS-$(CONFIG_GENERIC_CPU) +=3D $(call cc-option,-mcpu=3Dpower5,-mcpu=3D= power4) endif -else +else ifdef CONFIG_PPC_BOOK3E_64 CFLAGS-$(CONFIG_GENERIC_CPU) +=3D -mcpu=3Dpowerpc64 endif =20 diff --git a/arch/powerpc/boot/dts/fsl/t1040rdb-rev-a.dts b/arch/powerpc/bo= ot/dts/fsl/t1040rdb-rev-a.dts new file mode 100644 index 000000000000..73f8c998c64d --- /dev/null +++ b/arch/powerpc/boot/dts/fsl/t1040rdb-rev-a.dts @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * T1040RDB-REV-A Device Tree Source + * + * Copyright 2014 - 2015 Freescale Semiconductor Inc. + * + */ + +#include "t1040rdb.dts" + +/ { + model =3D "fsl,T1040RDB-REV-A"; + compatible =3D "fsl,T1040RDB-REV-A"; +}; + +&seville_port0 { + label =3D "ETH5"; +}; + +&seville_port2 { + label =3D "ETH7"; +}; + +&seville_port4 { + label =3D "ETH9"; +}; + +&seville_port6 { + label =3D "ETH11"; +}; diff --git a/arch/powerpc/boot/dts/fsl/t1040rdb.dts b/arch/powerpc/boot/dts= /fsl/t1040rdb.dts index af0c8a6f5613..b6733e7e6580 100644 --- a/arch/powerpc/boot/dts/fsl/t1040rdb.dts +++ b/arch/powerpc/boot/dts/fsl/t1040rdb.dts @@ -119,7 +119,7 @@ &seville_port0 { managed =3D "in-band-status"; phy-handle =3D <&phy_qsgmii_0>; phy-mode =3D "qsgmii"; - label =3D "ETH5"; + label =3D "ETH3"; status =3D "okay"; }; =20 @@ -135,7 +135,7 @@ &seville_port2 { managed =3D "in-band-status"; phy-handle =3D <&phy_qsgmii_2>; phy-mode =3D "qsgmii"; - label =3D "ETH7"; + label =3D "ETH5"; status =3D "okay"; }; =20 @@ -151,7 +151,7 @@ &seville_port4 { managed =3D "in-band-status"; phy-handle =3D <&phy_qsgmii_4>; phy-mode =3D "qsgmii"; - label =3D "ETH9"; + label =3D "ETH7"; status =3D "okay"; }; =20 @@ -167,7 +167,7 @@ &seville_port6 { managed =3D "in-band-status"; phy-handle =3D <&phy_qsgmii_6>; phy-mode =3D "qsgmii"; - label =3D "ETH11"; + label =3D "ETH9"; status =3D "okay"; }; =20 diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h index beba4979bff9..fee979d3a1aa 100644 --- a/arch/powerpc/include/asm/io.h +++ b/arch/powerpc/include/asm/io.h @@ -359,25 +359,37 @@ static inline void __raw_writeq_be(unsigned long v, v= olatile void __iomem *addr) */ static inline void __raw_rm_writeb(u8 val, volatile void __iomem *paddr) { - __asm__ __volatile__("stbcix %0,0,%1" + __asm__ __volatile__(".machine push; \ + .machine power6; \ + stbcix %0,0,%1; \ + .machine pop;" : : "r" (val), "r" (paddr) : "memory"); } =20 static inline void __raw_rm_writew(u16 val, volatile void __iomem *paddr) { - __asm__ __volatile__("sthcix %0,0,%1" + __asm__ __volatile__(".machine push; \ + .machine power6; \ + sthcix %0,0,%1; \ + .machine pop;" : : "r" (val), "r" (paddr) : "memory"); } =20 static inline void __raw_rm_writel(u32 val, volatile void __iomem *paddr) { - __asm__ __volatile__("stwcix %0,0,%1" + __asm__ __volatile__(".machine push; \ + .machine power6; \ + stwcix %0,0,%1; \ + .machine pop;" : : "r" (val), "r" (paddr) : "memory"); } =20 static inline void __raw_rm_writeq(u64 val, volatile void __iomem *paddr) { - __asm__ __volatile__("stdcix %0,0,%1" + __asm__ __volatile__(".machine push; \ + .machine power6; \ + stdcix %0,0,%1; \ + .machine pop;" : : "r" (val), "r" (paddr) : "memory"); } =20 @@ -389,7 +401,10 @@ static inline void __raw_rm_writeq_be(u64 val, volatil= e void __iomem *paddr) static inline u8 __raw_rm_readb(volatile void __iomem *paddr) { u8 ret; - __asm__ __volatile__("lbzcix %0,0, %1" + __asm__ __volatile__(".machine push; \ + .machine power6; \ + lbzcix %0,0, %1; \ + .machine pop;" : "=3Dr" (ret) : "r" (paddr) : "memory"); return ret; } @@ -397,7 +412,10 @@ static inline u8 __raw_rm_readb(volatile void __iomem = *paddr) static inline u16 __raw_rm_readw(volatile void __iomem *paddr) { u16 ret; - __asm__ __volatile__("lhzcix %0,0, %1" + __asm__ __volatile__(".machine push; \ + .machine power6; \ + lhzcix %0,0, %1; \ + .machine pop;" : "=3Dr" (ret) : "r" (paddr) : "memory"); return ret; } @@ -405,7 +423,10 @@ static inline u16 __raw_rm_readw(volatile void __iomem= *paddr) static inline u32 __raw_rm_readl(volatile void __iomem *paddr) { u32 ret; - __asm__ __volatile__("lwzcix %0,0, %1" + __asm__ __volatile__(".machine push; \ + .machine power6; \ + lwzcix %0,0, %1; \ + .machine pop;" : "=3Dr" (ret) : "r" (paddr) : "memory"); return ret; } @@ -413,7 +434,10 @@ static inline u32 __raw_rm_readl(volatile void __iomem= *paddr) static inline u64 __raw_rm_readq(volatile void __iomem *paddr) { u64 ret; - __asm__ __volatile__("ldcix %0,0, %1" + __asm__ __volatile__(".machine push; \ + .machine power6; \ + ldcix %0,0, %1; \ + .machine pop;" : "=3Dr" (ret) : "r" (paddr) : "memory"); return ret; } diff --git a/arch/powerpc/include/asm/set_memory.h b/arch/powerpc/include/a= sm/set_memory.h index b040094f7920..7ebc807aa8cc 100644 --- a/arch/powerpc/include/asm/set_memory.h +++ b/arch/powerpc/include/asm/set_memory.h @@ -6,6 +6,8 @@ #define SET_MEMORY_RW 1 #define SET_MEMORY_NX 2 #define SET_MEMORY_X 3 +#define SET_MEMORY_NP 4 /* Set memory non present */ +#define SET_MEMORY_P 5 /* Set memory present */ =20 int change_memory_attr(unsigned long addr, int numpages, long action); =20 @@ -29,6 +31,14 @@ static inline int set_memory_x(unsigned long addr, int n= umpages) return change_memory_attr(addr, numpages, SET_MEMORY_X); } =20 -int set_memory_attr(unsigned long addr, int numpages, pgprot_t prot); +static inline int set_memory_np(unsigned long addr, int numpages) +{ + return change_memory_attr(addr, numpages, SET_MEMORY_NP); +} + +static inline int set_memory_p(unsigned long addr, int numpages) +{ + return change_memory_attr(addr, numpages, SET_MEMORY_P); +} =20 #endif diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/= uaccess.h index 63316100080c..4a35423f766d 100644 --- a/arch/powerpc/include/asm/uaccess.h +++ b/arch/powerpc/include/asm/uaccess.h @@ -125,8 +125,11 @@ do { \ */ #define __get_user_atomic_128_aligned(kaddr, uaddr, err) \ __asm__ __volatile__( \ + ".machine push\n" \ + ".machine altivec\n" \ "1: lvx 0,0,%1 # get user\n" \ " stvx 0,0,%2 # put kernel\n" \ + ".machine pop\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ "3: li %0,%3\n" \ diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index a2fd1db29f7e..7fa685711669 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -6101,8 +6101,11 @@ static int kvmppc_book3s_init_hv(void) if (r) return r; =20 - if (kvmppc_radix_possible()) + if (kvmppc_radix_possible()) { r =3D kvmppc_radix_init(); + if (r) + return r; + } =20 r =3D kvmppc_uvmem_init(); if (r < 0) diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index a72920f4f221..8d91a50a84a8 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -1507,7 +1507,7 @@ int kvmppc_handle_vmx_load(struct kvm_vcpu *vcpu, { enum emulation_result emulated =3D EMULATE_DONE; =20 - if (vcpu->arch.mmio_vsx_copy_nums > 2) + if (vcpu->arch.mmio_vmx_copy_nums > 2) return EMULATE_FAIL; =20 while (vcpu->arch.mmio_vmx_copy_nums) { @@ -1604,7 +1604,7 @@ int kvmppc_handle_vmx_store(struct kvm_vcpu *vcpu, unsigned int index =3D rs & KVM_MMIO_REG_MASK; enum emulation_result emulated =3D EMULATE_DONE; =20 - if (vcpu->arch.mmio_vsx_copy_nums > 2) + if (vcpu->arch.mmio_vmx_copy_nums > 2) return EMULATE_FAIL; =20 vcpu->arch.io_gpr =3D rs; diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index b042fcae3913..6417893bae5d 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c @@ -112,9 +112,9 @@ static nokprobe_inline long address_ok(struct pt_regs *= regs, { if (!user_mode(regs)) return 1; - if (__access_ok(ea, nb)) + if (access_ok((void __user *)ea, nb)) return 1; - if (__access_ok(ea, 1)) + if (access_ok((void __user *)ea, 1)) /* Access overlaps the end of the user region */ regs->dar =3D TASK_SIZE_MAX - 1; else @@ -1097,7 +1097,10 @@ NOKPROBE_SYMBOL(emulate_dcbz); =20 #define __put_user_asmx(x, addr, err, op, cr) \ __asm__ __volatile__( \ + ".machine push\n" \ + ".machine power8\n" \ "1: " op " %2,0,%3\n" \ + ".machine pop\n" \ " mfcr %1\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ @@ -1110,7 +1113,10 @@ NOKPROBE_SYMBOL(emulate_dcbz); =20 #define __get_user_asmx(x, addr, err, op) \ __asm__ __volatile__( \ + ".machine push\n" \ + ".machine power8\n" \ "1: "op" %1,0,%2\n" \ + ".machine pop\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ "3: li %0,%3\n" \ @@ -3389,7 +3395,7 @@ int emulate_loadstore(struct pt_regs *regs, struct in= struction_op *op) __put_user_asmx(op->val, ea, err, "stbcx.", cr); break; case 2: - __put_user_asmx(op->val, ea, err, "stbcx.", cr); + __put_user_asmx(op->val, ea, err, "sthcx.", cr); break; #endif case 4: diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index a8d0ce85d39a..4a15172dfef2 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -568,18 +568,24 @@ NOKPROBE_SYMBOL(hash__do_page_fault); static void __bad_page_fault(struct pt_regs *regs, int sig) { int is_write =3D page_fault_is_write(regs->dsisr); + const char *msg; =20 /* kernel has accessed a bad area */ =20 + if (regs->dar < PAGE_SIZE) + msg =3D "Kernel NULL pointer dereference"; + else + msg =3D "Unable to handle kernel data access"; + switch (TRAP(regs)) { case INTERRUPT_DATA_STORAGE: - case INTERRUPT_DATA_SEGMENT: case INTERRUPT_H_DATA_STORAGE: - pr_alert("BUG: %s on %s at 0x%08lx\n", - regs->dar < PAGE_SIZE ? "Kernel NULL pointer dereference" : - "Unable to handle kernel data access", + pr_alert("BUG: %s on %s at 0x%08lx\n", msg, is_write ? "write" : "read", regs->dar); break; + case INTERRUPT_DATA_SEGMENT: + pr_alert("BUG: %s at 0x%08lx\n", msg, regs->dar); + break; case INTERRUPT_INST_STORAGE: case INTERRUPT_INST_SEGMENT: pr_alert("BUG: Unable to handle kernel instruction fetch%s", diff --git a/arch/powerpc/mm/kasan/kasan_init_32.c b/arch/powerpc/mm/kasan/= kasan_init_32.c index cf8770b1a692..f3e4d069e0ba 100644 --- a/arch/powerpc/mm/kasan/kasan_init_32.c +++ b/arch/powerpc/mm/kasan/kasan_init_32.c @@ -83,13 +83,12 @@ void __init kasan_update_early_region(unsigned long k_start, unsigned long k_end, pte_= t pte) { unsigned long k_cur; - phys_addr_t pa =3D __pa(kasan_early_shadow_page); =20 for (k_cur =3D k_start; k_cur !=3D k_end; k_cur +=3D PAGE_SIZE) { pmd_t *pmd =3D pmd_off_k(k_cur); pte_t *ptep =3D pte_offset_kernel(pmd, k_cur); =20 - if ((pte_val(*ptep) & PTE_RPN_MASK) !=3D pa) + if (pte_page(*ptep) !=3D virt_to_page(lm_alias(kasan_early_shadow_page))) continue; =20 __set_pte_at(&init_mm, k_cur, ptep, pte, 0); diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 59d3cfcd7887..5fb829256b59 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -956,7 +956,9 @@ static int __init parse_numa_properties(void) of_node_put(cpu); } =20 - node_set_online(nid); + /* node_set_online() is an UB if 'nid' is negative */ + if (likely(nid >=3D 0)) + node_set_online(nid); } =20 get_n_mem_cells(&n_mem_addr_cells, &n_mem_size_cells); diff --git a/arch/powerpc/mm/pageattr.c b/arch/powerpc/mm/pageattr.c index edea388e9d3f..3bb9d168e3b3 100644 --- a/arch/powerpc/mm/pageattr.c +++ b/arch/powerpc/mm/pageattr.c @@ -48,6 +48,12 @@ static int change_page_attr(pte_t *ptep, unsigned long a= ddr, void *data) case SET_MEMORY_X: pte =3D pte_mkexec(pte); break; + case SET_MEMORY_NP: + pte_update(&init_mm, addr, ptep, _PAGE_PRESENT, 0, 0); + break; + case SET_MEMORY_P: + pte_update(&init_mm, addr, ptep, 0, _PAGE_PRESENT, 0); + break; default: WARN_ON_ONCE(1); break; @@ -96,36 +102,3 @@ int change_memory_attr(unsigned long addr, int numpages= , long action) return apply_to_existing_page_range(&init_mm, start, size, change_page_attr, (void *)action); } - -/* - * Set the attributes of a page: - * - * This function is used by PPC32 at the end of init to set final kernel m= emory - * protection. It includes changing the maping of the page it is executing= from - * and data pages it is using. - */ -static int set_page_attr(pte_t *ptep, unsigned long addr, void *data) -{ - pgprot_t prot =3D __pgprot((unsigned long)data); - - spin_lock(&init_mm.page_table_lock); - - set_pte_at(&init_mm, addr, ptep, pte_modify(*ptep, prot)); - flush_tlb_kernel_range(addr, addr + PAGE_SIZE); - - spin_unlock(&init_mm.page_table_lock); - - return 0; -} - -int set_memory_attr(unsigned long addr, int numpages, pgprot_t prot) -{ - unsigned long start =3D ALIGN_DOWN(addr, PAGE_SIZE); - unsigned long sz =3D numpages * PAGE_SIZE; - - if (numpages <=3D 0) - return 0; - - return apply_to_existing_page_range(&init_mm, start, sz, set_page_attr, - (void *)pgprot_val(prot)); -} diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 906e4e4328b2..f71ededdc02a 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -135,10 +135,12 @@ void mark_initmem_nx(void) unsigned long numpages =3D PFN_UP((unsigned long)_einittext) - PFN_DOWN((unsigned long)_sinittext); =20 - if (v_block_mapped((unsigned long)_sinittext)) + if (v_block_mapped((unsigned long)_sinittext)) { mmu_mark_initmem_nx(); - else - set_memory_attr((unsigned long)_sinittext, numpages, PAGE_KERNEL); + } else { + set_memory_nx((unsigned long)_sinittext, numpages); + set_memory_rw((unsigned long)_sinittext, numpages); + } } =20 #ifdef CONFIG_STRICT_KERNEL_RWX @@ -152,18 +154,14 @@ void mark_rodata_ro(void) return; } =20 - numpages =3D PFN_UP((unsigned long)_etext) - - PFN_DOWN((unsigned long)_stext); - - set_memory_attr((unsigned long)_stext, numpages, PAGE_KERNEL_ROX); /* - * mark .rodata as read only. Use __init_begin rather than __end_rodata - * to cover NOTES and EXCEPTION_TABLE. + * mark .text and .rodata as read only. Use __init_begin rather than + * __end_rodata to cover NOTES and EXCEPTION_TABLE. */ numpages =3D PFN_UP((unsigned long)__init_begin) - - PFN_DOWN((unsigned long)__start_rodata); + PFN_DOWN((unsigned long)_stext); =20 - set_memory_attr((unsigned long)__start_rodata, numpages, PAGE_KERNEL_RO); + set_memory_ro((unsigned long)_stext, numpages); =20 // mark_initmem_nx() should have already run by now ptdump_check_wx(); @@ -179,8 +177,8 @@ void __kernel_map_pages(struct page *page, int numpages= , int enable) return; =20 if (enable) - set_memory_attr(addr, numpages, PAGE_KERNEL); + set_memory_p(addr, numpages); else - set_memory_attr(addr, numpages, __pgprot(0)); + set_memory_np(addr, numpages); } #endif /* CONFIG_DEBUG_PAGEALLOC */ diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c index e106909ff9c3..e7583fbcc8fa 100644 --- a/arch/powerpc/perf/imc-pmu.c +++ b/arch/powerpc/perf/imc-pmu.c @@ -1457,7 +1457,11 @@ static int trace_imc_event_init(struct perf_event *e= vent) =20 event->hw.idx =3D -1; =20 - event->pmu->task_ctx_nr =3D perf_hw_context; + /* + * There can only be a single PMU for perf_hw_context events which is ass= igned to + * core PMU. Hence use "perf_sw_context" for trace_imc. + */ + event->pmu->task_ctx_nr =3D perf_sw_context; event->destroy =3D reset_global_refc; return 0; } diff --git a/arch/powerpc/platforms/8xx/pic.c b/arch/powerpc/platforms/8xx/= pic.c index f2ba837249d6..04a6abf14c29 100644 --- a/arch/powerpc/platforms/8xx/pic.c +++ b/arch/powerpc/platforms/8xx/pic.c @@ -153,6 +153,7 @@ int __init mpc8xx_pic_init(void) if (mpc8xx_pic_host =3D=3D NULL) { printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n"); ret =3D -ENOMEM; + goto out; } =20 ret =3D 0; diff --git a/arch/powerpc/platforms/powernv/rng.c b/arch/powerpc/platforms/= powernv/rng.c index 72c25295c1c2..69c344c8884f 100644 --- a/arch/powerpc/platforms/powernv/rng.c +++ b/arch/powerpc/platforms/powernv/rng.c @@ -43,7 +43,11 @@ static unsigned long rng_whiten(struct powernv_rng *rng,= unsigned long val) unsigned long parity; =20 /* Calculate the parity of the value */ - asm ("popcntd %0,%1" : "=3Dr" (parity) : "r" (val)); + asm (".machine push; \ + .machine power7; \ + popcntd %0,%1; \ + .machine pop;" + : "=3Dr" (parity) : "r" (val)); =20 /* xor our value with the previous mask */ val ^=3D rng->mask; diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/plat= forms/pseries/pci_dlpar.c index 90c9d3531694..4ba824568119 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -78,6 +78,9 @@ int remove_phb_dynamic(struct pci_controller *phb) =20 pseries_msi_free_domains(phb); =20 + /* Keep a reference so phb isn't freed yet */ + get_device(&host_bridge->dev); + /* Remove the PCI bus and unregister the bridge device from sysfs */ phb->bus =3D NULL; pci_remove_bus(b); @@ -101,6 +104,7 @@ int remove_phb_dynamic(struct pci_controller *phb) * the pcibios_free_controller_deferred() callback; * see pseries_root_bridge_prepare(). */ + put_device(&host_bridge->dev); =20 return 0; } diff --git a/arch/powerpc/sysdev/fsl_gtm.c b/arch/powerpc/sysdev/fsl_gtm.c index 8963eaffb1b7..39186ad6b3c3 100644 --- a/arch/powerpc/sysdev/fsl_gtm.c +++ b/arch/powerpc/sysdev/fsl_gtm.c @@ -86,7 +86,7 @@ static LIST_HEAD(gtms); */ struct gtm_timer *gtm_get_timer16(void) { - struct gtm *gtm =3D NULL; + struct gtm *gtm; int i; =20 list_for_each_entry(gtm, >ms, list_node) { @@ -103,7 +103,7 @@ struct gtm_timer *gtm_get_timer16(void) spin_unlock_irq(>m->lock); } =20 - if (gtm) + if (!list_empty(>ms)) return ERR_PTR(-EBUSY); return ERR_PTR(-ENODEV); } diff --git a/arch/riscv/boot/dts/canaan/sipeed_maix_bit.dts b/arch/riscv/bo= ot/dts/canaan/sipeed_maix_bit.dts index 0bcaf35045e7..82e7f8069ae7 100644 --- a/arch/riscv/boot/dts/canaan/sipeed_maix_bit.dts +++ b/arch/riscv/boot/dts/canaan/sipeed_maix_bit.dts @@ -203,6 +203,8 @@ spi-flash@0 { compatible =3D "jedec,spi-nor"; reg =3D <0>; spi-max-frequency =3D <50000000>; + spi-tx-bus-width =3D <4>; + spi-rx-bus-width =3D <4>; m25p,fast-read; broken-flash-reset; }; diff --git a/arch/riscv/boot/dts/canaan/sipeed_maix_dock.dts b/arch/riscv/b= oot/dts/canaan/sipeed_maix_dock.dts index ac8a03f5867a..8d335233853a 100644 --- a/arch/riscv/boot/dts/canaan/sipeed_maix_dock.dts +++ b/arch/riscv/boot/dts/canaan/sipeed_maix_dock.dts @@ -205,6 +205,8 @@ spi-flash@0 { compatible =3D "jedec,spi-nor"; reg =3D <0>; spi-max-frequency =3D <50000000>; + spi-tx-bus-width =3D <4>; + spi-rx-bus-width =3D <4>; m25p,fast-read; broken-flash-reset; }; diff --git a/arch/riscv/boot/dts/canaan/sipeed_maix_go.dts b/arch/riscv/boo= t/dts/canaan/sipeed_maix_go.dts index 623998194bc1..6703cfc05588 100644 --- a/arch/riscv/boot/dts/canaan/sipeed_maix_go.dts +++ b/arch/riscv/boot/dts/canaan/sipeed_maix_go.dts @@ -213,6 +213,8 @@ spi-flash@0 { compatible =3D "jedec,spi-nor"; reg =3D <0>; spi-max-frequency =3D <50000000>; + spi-tx-bus-width =3D <4>; + spi-rx-bus-width =3D <4>; m25p,fast-read; broken-flash-reset; }; diff --git a/arch/riscv/boot/dts/canaan/sipeed_maixduino.dts b/arch/riscv/b= oot/dts/canaan/sipeed_maixduino.dts index cf605ba0d67e..ac0b56f7d2c9 100644 --- a/arch/riscv/boot/dts/canaan/sipeed_maixduino.dts +++ b/arch/riscv/boot/dts/canaan/sipeed_maixduino.dts @@ -178,6 +178,8 @@ spi-flash@0 { compatible =3D "jedec,spi-nor"; reg =3D <0>; spi-max-frequency =3D <50000000>; + spi-tx-bus-width =3D <4>; + spi-rx-bus-width =3D <4>; m25p,fast-read; broken-flash-reset; }; diff --git a/arch/riscv/include/asm/module.lds.h b/arch/riscv/include/asm/m= odule.lds.h index 4254ff2ff049..1075beae1ac6 100644 --- a/arch/riscv/include/asm/module.lds.h +++ b/arch/riscv/include/asm/module.lds.h @@ -2,8 +2,8 @@ /* Copyright (C) 2017 Andes Technology Corporation */ #ifdef CONFIG_MODULE_SECTIONS SECTIONS { - .plt (NOLOAD) : { BYTE(0) } - .got (NOLOAD) : { BYTE(0) } - .got.plt (NOLOAD) : { BYTE(0) } + .plt : { BYTE(0) } + .got : { BYTE(0) } + .got.plt : { BYTE(0) } } #endif diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/= thread_info.h index 60da0dcacf14..74d888c8d631 100644 --- a/arch/riscv/include/asm/thread_info.h +++ b/arch/riscv/include/asm/thread_info.h @@ -11,11 +11,17 @@ #include #include =20 +#ifdef CONFIG_KASAN +#define KASAN_STACK_ORDER 1 +#else +#define KASAN_STACK_ORDER 0 +#endif + /* thread information allocation */ #ifdef CONFIG_64BIT -#define THREAD_SIZE_ORDER (2) +#define THREAD_SIZE_ORDER (2 + KASAN_STACK_ORDER) #else -#define THREAD_SIZE_ORDER (1) +#define THREAD_SIZE_ORDER (1 + KASAN_STACK_ORDER) #endif #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) =20 diff --git a/arch/riscv/kernel/perf_callchain.c b/arch/riscv/kernel/perf_ca= llchain.c index 8ecfc4c128bc..357f985041cb 100644 --- a/arch/riscv/kernel/perf_callchain.c +++ b/arch/riscv/kernel/perf_callchain.c @@ -15,8 +15,8 @@ static unsigned long user_backtrace(struct perf_callchain= _entry_ctx *entry, { struct stackframe buftail; unsigned long ra =3D 0; - unsigned long *user_frame_tail =3D - (unsigned long *)(fp - sizeof(struct stackframe)); + unsigned long __user *user_frame_tail =3D + (unsigned long __user *)(fp - sizeof(struct stackframe)); =20 /* Check accessibility of one struct frame_tail beyond */ if (!access_ok(user_frame_tail, sizeof(buftail))) @@ -73,7 +73,7 @@ void perf_callchain_user(struct perf_callchain_entry_ctx = *entry, =20 static bool fill_callchain(void *entry, unsigned long pc) { - return perf_callchain_store(entry, pc); + return perf_callchain_store(entry, pc) =3D=3D 0; } =20 void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index ffab16369bea..74f80443b195 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c @@ -65,7 +65,7 @@ struct rt_signal_frame { */ static inline bool invalid_frame_pointer(void __user *fp, int fplen) { - if ((((unsigned long) fp) & 15) || !__access_ok((unsigned long)fp, fplen)) + if ((((unsigned long) fp) & 15) || !access_ok(fp, fplen)) return true; =20 return false; diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_ker= n.c index 6ead1e240457..8ca67a692683 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -224,7 +224,7 @@ void mconsole_go(struct mc_request *req) =20 void mconsole_stop(struct mc_request *req) { - deactivate_fd(req->originating_fd, MCONSOLE_IRQ); + block_signals(); os_set_fd_block(req->originating_fd, 1); mconsole_reply(req, "stopped", 0, 0); for (;;) { @@ -247,6 +247,7 @@ void mconsole_stop(struct mc_request *req) } os_set_fd_block(req->originating_fd, 0); mconsole_reply(req, "", 0, 0); + unblock_signals(); } =20 static DEFINE_SPINLOCK(mc_devices_lock); diff --git a/arch/x86/events/intel/pt.c b/arch/x86/events/intel/pt.c index 2d33bba9a144..215aed65e978 100644 --- a/arch/x86/events/intel/pt.c +++ b/arch/x86/events/intel/pt.c @@ -472,7 +472,7 @@ static u64 pt_config_filters(struct perf_event *event) pt->filters.filter[range].msr_b =3D filter->msr_b; } =20 - rtit_ctl |=3D filter->config << pt_address_ranges[range].reg_off; + rtit_ctl |=3D (u64)filter->config << pt_address_ranges[range].reg_off; } =20 return rtit_ctl; diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index ff3db164e52c..a9bc113c512a 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -515,7 +515,7 @@ static void __send_ipi_mask(const struct cpumask *mask,= int vector) } else if (apic_id < min && max - apic_id < KVM_IPI_CLUSTER_SIZE) { ipi_bitmap <<=3D min - apic_id; min =3D apic_id; - } else if (apic_id < min + KVM_IPI_CLUSTER_SIZE) { + } else if (apic_id > min && apic_id < min + KVM_IPI_CLUSTER_SIZE) { max =3D apic_id < max ? max : apic_id; } else { ret =3D kvm_hypercall4(KVM_HC_SEND_IPI, (unsigned long)ipi_bitmap, diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 28b1a4e57827..5705446c1213 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -1614,11 +1614,6 @@ static int __load_segment_descriptor(struct x86_emul= ate_ctxt *ctxt, goto exception; } =20 - if (!seg_desc.p) { - err_vec =3D (seg =3D=3D VCPU_SREG_SS) ? SS_VECTOR : NP_VECTOR; - goto exception; - } - dpl =3D seg_desc.dpl; =20 switch (seg) { @@ -1658,6 +1653,10 @@ static int __load_segment_descriptor(struct x86_emul= ate_ctxt *ctxt, case VCPU_SREG_TR: if (seg_desc.s || (seg_desc.type !=3D 1 && seg_desc.type !=3D 9)) goto exception; + if (!seg_desc.p) { + err_vec =3D NP_VECTOR; + goto exception; + } old_desc =3D seg_desc; seg_desc.type |=3D 2; /* busy */ ret =3D ctxt->ops->cmpxchg_emulated(ctxt, desc_addr, &old_desc, &seg_des= c, @@ -1682,6 +1681,11 @@ static int __load_segment_descriptor(struct x86_emul= ate_ctxt *ctxt, break; } =20 + if (!seg_desc.p) { + err_vec =3D (seg =3D=3D VCPU_SREG_SS) ? SS_VECTOR : NP_VECTOR; + goto exception; + } + if (seg_desc.s) { /* mark segment as accessed */ if (!(seg_desc.type & 1)) { diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 8d8c1cc7cb53..31116e277b42 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -236,7 +236,7 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *syni= c, struct kvm_vcpu *vcpu =3D hv_synic_to_vcpu(synic); int ret; =20 - if (!synic->active && !host) + if (!synic->active && (!host || data)) return 1; =20 trace_kvm_hv_synic_set_msr(vcpu->vcpu_id, msr, data, host); @@ -282,6 +282,9 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *syni= c, case HV_X64_MSR_EOM: { int i; =20 + if (!synic->active) + break; + for (i =3D 0; i < ARRAY_SIZE(synic->sint); i++) kvm_hv_notify_acked_sint(vcpu, i); break; @@ -446,6 +449,9 @@ static int synic_set_irq(struct kvm_vcpu_hv_synic *syni= c, u32 sint) struct kvm_lapic_irq irq; int ret, vector; =20 + if (KVM_BUG_ON(!lapic_in_kernel(vcpu), vcpu->kvm)) + return -EINVAL; + if (sint >=3D ARRAY_SIZE(synic->sint)) return -EINVAL; =20 @@ -658,7 +664,7 @@ static int stimer_set_config(struct kvm_vcpu_hv_stimer = *stimer, u64 config, struct kvm_vcpu_hv *hv_vcpu =3D to_hv_vcpu(vcpu); struct kvm_vcpu_hv_synic *synic =3D to_hv_synic(vcpu); =20 - if (!synic->active && !host) + if (!synic->active && (!host || config)) return 1; =20 if (unlikely(!host && hv_vcpu->enforce_cpuid && new_config.direct_mode && @@ -687,7 +693,7 @@ static int stimer_set_count(struct kvm_vcpu_hv_stimer *= stimer, u64 count, struct kvm_vcpu *vcpu =3D hv_stimer_to_vcpu(stimer); struct kvm_vcpu_hv_synic *synic =3D to_hv_synic(vcpu); =20 - if (!synic->active && !host) + if (!synic->active && (!host || count)) return 1; =20 trace_kvm_hv_stimer_set_count(hv_stimer_to_vcpu(stimer)->vcpu_id, @@ -1749,7 +1755,7 @@ struct kvm_hv_hcall { sse128_t xmm[HV_HYPERCALL_MAX_XMM_REGISTERS]; }; =20 -static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc= , bool ex) +static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc) { int i; gpa_t gpa; @@ -1764,7 +1770,8 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, st= ruct kvm_hv_hcall *hc, bool int sparse_banks_len; bool all_cpus; =20 - if (!ex) { + if (hc->code =3D=3D HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST || + hc->code =3D=3D HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE) { if (hc->fast) { flush.address_space =3D hc->ingpa; flush.flags =3D hc->outgpa; @@ -1818,7 +1825,8 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, st= ruct kvm_hv_hcall *hc, bool =20 if (!all_cpus) { if (hc->fast) { - if (sparse_banks_len > HV_HYPERCALL_MAX_XMM_REGISTERS - 1) + /* XMM0 is already consumed, each XMM holds two sparse banks. */ + if (sparse_banks_len > 2 * (HV_HYPERCALL_MAX_XMM_REGISTERS - 1)) return HV_STATUS_INVALID_HYPERCALL_INPUT; for (i =3D 0; i < sparse_banks_len; i +=3D 2) { sparse_banks[i] =3D sse128_lo(hc->xmm[i / 2 + 1]); @@ -1874,7 +1882,7 @@ static void kvm_send_ipi_to_many(struct kvm *kvm, u32= vector, } } =20 -static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc,= bool ex) +static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc) { struct kvm *kvm =3D vcpu->kvm; struct hv_send_ipi_ex send_ipi_ex; @@ -1887,8 +1895,9 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, str= uct kvm_hv_hcall *hc, bool int sparse_banks_len; u32 vector; bool all_cpus; + int i; =20 - if (!ex) { + if (hc->code =3D=3D HVCALL_SEND_IPI) { if (!hc->fast) { if (unlikely(kvm_read_guest(kvm, hc->ingpa, &send_ipi, sizeof(send_ipi)))) @@ -1907,9 +1916,15 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, st= ruct kvm_hv_hcall *hc, bool =20 trace_kvm_hv_send_ipi(vector, sparse_banks[0]); } else { - if (unlikely(kvm_read_guest(kvm, hc->ingpa, &send_ipi_ex, - sizeof(send_ipi_ex)))) - return HV_STATUS_INVALID_HYPERCALL_INPUT; + if (!hc->fast) { + if (unlikely(kvm_read_guest(kvm, hc->ingpa, &send_ipi_ex, + sizeof(send_ipi_ex)))) + return HV_STATUS_INVALID_HYPERCALL_INPUT; + } else { + send_ipi_ex.vector =3D (u32)hc->ingpa; + send_ipi_ex.vp_set.format =3D hc->outgpa; + send_ipi_ex.vp_set.valid_bank_mask =3D sse128_lo(hc->xmm[0]); + } =20 trace_kvm_hv_send_ipi_ex(send_ipi_ex.vector, send_ipi_ex.vp_set.format, @@ -1917,8 +1932,7 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, str= uct kvm_hv_hcall *hc, bool =20 vector =3D send_ipi_ex.vector; valid_bank_mask =3D send_ipi_ex.vp_set.valid_bank_mask; - sparse_banks_len =3D bitmap_weight(&valid_bank_mask, 64) * - sizeof(sparse_banks[0]); + sparse_banks_len =3D bitmap_weight(&valid_bank_mask, 64); =20 all_cpus =3D send_ipi_ex.vp_set.format =3D=3D HV_GENERIC_SET_ALL; =20 @@ -1928,12 +1942,27 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, s= truct kvm_hv_hcall *hc, bool if (!sparse_banks_len) goto ret_success; =20 - if (kvm_read_guest(kvm, - hc->ingpa + offsetof(struct hv_send_ipi_ex, - vp_set.bank_contents), - sparse_banks, - sparse_banks_len)) - return HV_STATUS_INVALID_HYPERCALL_INPUT; + if (!hc->fast) { + if (kvm_read_guest(kvm, + hc->ingpa + offsetof(struct hv_send_ipi_ex, + vp_set.bank_contents), + sparse_banks, + sparse_banks_len * sizeof(sparse_banks[0]))) + return HV_STATUS_INVALID_HYPERCALL_INPUT; + } else { + /* + * The lower half of XMM0 is already consumed, each XMM holds + * two sparse banks. + */ + if (sparse_banks_len > (2 * HV_HYPERCALL_MAX_XMM_REGISTERS - 1)) + return HV_STATUS_INVALID_HYPERCALL_INPUT; + for (i =3D 0; i < sparse_banks_len; i++) { + if (i % 2) + sparse_banks[i] =3D sse128_lo(hc->xmm[(i + 1) / 2]); + else + sparse_banks[i] =3D sse128_hi(hc->xmm[i / 2]); + } + } } =20 check_and_send_ipi: @@ -2095,6 +2124,7 @@ static bool is_xmm_fast_hypercall(struct kvm_hv_hcall= *hc) case HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE: case HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX: case HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX: + case HVCALL_SEND_IPI_EX: return true; } =20 @@ -2246,46 +2276,28 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) kvm_hv_hypercall_complete_userspace; return 0; case HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST: - if (unlikely(!hc.rep_cnt || hc.rep_idx)) { - ret =3D HV_STATUS_INVALID_HYPERCALL_INPUT; - break; - } - ret =3D kvm_hv_flush_tlb(vcpu, &hc, false); - break; - case HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE: - if (unlikely(hc.rep)) { - ret =3D HV_STATUS_INVALID_HYPERCALL_INPUT; - break; - } - ret =3D kvm_hv_flush_tlb(vcpu, &hc, false); - break; case HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX: if (unlikely(!hc.rep_cnt || hc.rep_idx)) { ret =3D HV_STATUS_INVALID_HYPERCALL_INPUT; break; } - ret =3D kvm_hv_flush_tlb(vcpu, &hc, true); + ret =3D kvm_hv_flush_tlb(vcpu, &hc); break; + case HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE: case HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX: if (unlikely(hc.rep)) { ret =3D HV_STATUS_INVALID_HYPERCALL_INPUT; break; } - ret =3D kvm_hv_flush_tlb(vcpu, &hc, true); + ret =3D kvm_hv_flush_tlb(vcpu, &hc); break; case HVCALL_SEND_IPI: - if (unlikely(hc.rep)) { - ret =3D HV_STATUS_INVALID_HYPERCALL_INPUT; - break; - } - ret =3D kvm_hv_send_ipi(vcpu, &hc, false); - break; case HVCALL_SEND_IPI_EX: - if (unlikely(hc.fast || hc.rep)) { + if (unlikely(hc.rep)) { ret =3D HV_STATUS_INVALID_HYPERCALL_INPUT; break; } - ret =3D kvm_hv_send_ipi(vcpu, &hc, true); + ret =3D kvm_hv_send_ipi(vcpu, &hc); break; case HVCALL_POST_DEBUG_DATA: case HVCALL_RETRIEVE_DEBUG_DATA: diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index e8e383fbe886..5c7a033d39d1 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -987,6 +987,10 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, st= ruct kvm_lapic *src, *r =3D -1; =20 if (irq->shorthand =3D=3D APIC_DEST_SELF) { + if (KVM_BUG_ON(!src, kvm)) { + *r =3D 0; + return true; + } *r =3D kvm_apic_set_irq(src->vcpu, irq, dest_map); return true; } @@ -2242,10 +2246,7 @@ void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *= vcpu, u64 data) =20 void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8) { - struct kvm_lapic *apic =3D vcpu->arch.apic; - - apic_set_tpr(apic, ((cr8 & 0x0f) << 4) - | (kvm_lapic_get_reg(apic, APIC_TASKPRI) & 4)); + apic_set_tpr(vcpu->arch.apic, (cr8 & 0x0f) << 4); } =20 u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index 9ae6168d381e..f502fa3cb3b4 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -48,6 +48,7 @@ X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_PKE) =20 #define KVM_MMU_CR0_ROLE_BITS (X86_CR0_PG | X86_CR0_WP) +#define KVM_MMU_EFER_ROLE_BITS (EFER_LME | EFER_NX) =20 static __always_inline u64 rsvd_bits(int s, int e) { diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index 708a5d297fe1..c005905f2852 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -34,9 +34,8 @@ #define PT_HAVE_ACCESSED_DIRTY(mmu) true #ifdef CONFIG_X86_64 #define PT_MAX_FULL_LEVELS PT64_ROOT_MAX_LEVEL - #define CMPXCHG cmpxchg + #define CMPXCHG "cmpxchgq" #else - #define CMPXCHG cmpxchg64 #define PT_MAX_FULL_LEVELS 2 #endif #elif PTTYPE =3D=3D 32 @@ -52,7 +51,7 @@ #define PT_GUEST_DIRTY_SHIFT PT_DIRTY_SHIFT #define PT_GUEST_ACCESSED_SHIFT PT_ACCESSED_SHIFT #define PT_HAVE_ACCESSED_DIRTY(mmu) true - #define CMPXCHG cmpxchg + #define CMPXCHG "cmpxchgl" #elif PTTYPE =3D=3D PTTYPE_EPT #define pt_element_t u64 #define guest_walker guest_walkerEPT @@ -65,7 +64,9 @@ #define PT_GUEST_DIRTY_SHIFT 9 #define PT_GUEST_ACCESSED_SHIFT 8 #define PT_HAVE_ACCESSED_DIRTY(mmu) ((mmu)->ept_ad) - #define CMPXCHG cmpxchg64 + #ifdef CONFIG_X86_64 + #define CMPXCHG "cmpxchgq" + #endif #define PT_MAX_FULL_LEVELS PT64_ROOT_MAX_LEVEL #else #error Invalid PTTYPE value @@ -147,43 +148,39 @@ static int FNAME(cmpxchg_gpte)(struct kvm_vcpu *vcpu,= struct kvm_mmu *mmu, pt_element_t __user *ptep_user, unsigned index, pt_element_t orig_pte, pt_element_t new_pte) { - int npages; - pt_element_t ret; - pt_element_t *table; - struct page *page; - - npages =3D get_user_pages_fast((unsigned long)ptep_user, 1, FOLL_WRITE, &= page); - if (likely(npages =3D=3D 1)) { - table =3D kmap_atomic(page); - ret =3D CMPXCHG(&table[index], orig_pte, new_pte); - kunmap_atomic(table); - - kvm_release_page_dirty(page); - } else { - struct vm_area_struct *vma; - unsigned long vaddr =3D (unsigned long)ptep_user & PAGE_MASK; - unsigned long pfn; - unsigned long paddr; - - mmap_read_lock(current->mm); - vma =3D find_vma_intersection(current->mm, vaddr, vaddr + PAGE_SIZE); - if (!vma || !(vma->vm_flags & VM_PFNMAP)) { - mmap_read_unlock(current->mm); - return -EFAULT; - } - pfn =3D ((vaddr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; - paddr =3D pfn << PAGE_SHIFT; - table =3D memremap(paddr, PAGE_SIZE, MEMREMAP_WB); - if (!table) { - mmap_read_unlock(current->mm); - return -EFAULT; - } - ret =3D CMPXCHG(&table[index], orig_pte, new_pte); - memunmap(table); - mmap_read_unlock(current->mm); - } + int r =3D -EFAULT; =20 - return (ret !=3D orig_pte); + if (!user_access_begin(ptep_user, sizeof(pt_element_t))) + return -EFAULT; + +#ifdef CMPXCHG + asm volatile("1:" LOCK_PREFIX CMPXCHG " %[new], %[ptr]\n" + "mov $0, %[r]\n" + "setnz %b[r]\n" + "2:" + _ASM_EXTABLE_UA(1b, 2b) + : [ptr] "+m" (*ptep_user), + [old] "+a" (orig_pte), + [r] "+q" (r) + : [new] "r" (new_pte) + : "memory"); +#else + asm volatile("1:" LOCK_PREFIX "cmpxchg8b %[ptr]\n" + "movl $0, %[r]\n" + "jz 2f\n" + "incl %[r]\n" + "2:" + _ASM_EXTABLE_UA(1b, 2b) + : [ptr] "+m" (*ptep_user), + [old] "+A" (orig_pte), + [r] "+rm" (r) + : [new_lo] "b" ((u32)new_pte), + [new_hi] "c" ((u32)(new_pte >> 32)) + : "memory"); +#endif + + user_access_end(); + return r; } =20 static bool FNAME(prefetch_invalid_gpte)(struct kvm_vcpu *vcpu, diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 095b5cb4e3c9..0f0ec2c33b72 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -99,15 +99,18 @@ void kvm_tdp_mmu_put_root(struct kvm *kvm, struct kvm_m= mu_page *root, } =20 /* - * Finds the next valid root after root (or the first valid root if root - * is NULL), takes a reference on it, and returns that next root. If root - * is not NULL, this thread should have already taken a reference on it, a= nd - * that reference will be dropped. If no valid root is found, this - * function will return NULL. + * Returns the next root after @prev_root (or the first root if @prev_root= is + * NULL). A reference to the returned root is acquired, and the reference= to + * @prev_root is released (the caller obviously must hold a reference to + * @prev_root if it's non-NULL). + * + * If @only_valid is true, invalid roots are skipped. + * + * Returns NULL if the end of tdp_mmu_roots was reached. */ static struct kvm_mmu_page *tdp_mmu_next_root(struct kvm *kvm, struct kvm_mmu_page *prev_root, - bool shared) + bool shared, bool only_valid) { struct kvm_mmu_page *next_root; =20 @@ -121,9 +124,14 @@ static struct kvm_mmu_page *tdp_mmu_next_root(struct k= vm *kvm, next_root =3D list_first_or_null_rcu(&kvm->arch.tdp_mmu_roots, typeof(*next_root), link); =20 - while (next_root && !kvm_tdp_mmu_get_root(kvm, next_root)) + while (next_root) { + if ((!only_valid || !next_root->role.invalid) && + kvm_tdp_mmu_get_root(kvm, next_root)) + break; + next_root =3D list_next_or_null_rcu(&kvm->arch.tdp_mmu_roots, &next_root->link, typeof(*next_root), link); + } =20 rcu_read_unlock(); =20 @@ -143,13 +151,19 @@ static struct kvm_mmu_page *tdp_mmu_next_root(struct = kvm *kvm, * mode. In the unlikely event that this thread must free a root, the lock * will be temporarily dropped and reacquired in write mode. */ -#define for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _shared) \ - for (_root =3D tdp_mmu_next_root(_kvm, NULL, _shared); \ - _root; \ - _root =3D tdp_mmu_next_root(_kvm, _root, _shared)) \ - if (kvm_mmu_page_as_id(_root) !=3D _as_id) { \ +#define __for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _shared, _= only_valid)\ + for (_root =3D tdp_mmu_next_root(_kvm, NULL, _shared, _only_valid); \ + _root; \ + _root =3D tdp_mmu_next_root(_kvm, _root, _shared, _only_valid)) \ + if (kvm_mmu_page_as_id(_root) !=3D _as_id) { \ } else =20 +#define for_each_valid_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _share= d) \ + __for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _shared, true) + +#define for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _shared) \ + __for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _shared, false) + #define for_each_tdp_mmu_root(_kvm, _root, _as_id) \ list_for_each_entry_rcu(_root, &_kvm->arch.tdp_mmu_roots, link, \ lockdep_is_held_type(&kvm->mmu_lock, 0) || \ @@ -200,7 +214,10 @@ hpa_t kvm_tdp_mmu_get_vcpu_root_hpa(struct kvm_vcpu *v= cpu) =20 role =3D page_role_for_level(vcpu, vcpu->arch.mmu->shadow_root_level); =20 - /* Check for an existing root before allocating a new one. */ + /* + * Check for an existing root before allocating a new one. Note, the + * role check prevents consuming an invalid root. + */ for_each_tdp_mmu_root(kvm, root, kvm_mmu_role_as_id(role)) { if (root->role.word =3D=3D role.word && kvm_tdp_mmu_get_root(kvm, root)) @@ -1032,13 +1049,8 @@ int kvm_tdp_mmu_map(struct kvm_vcpu *vcpu, struct kv= m_page_fault *fault) bool kvm_tdp_mmu_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *ra= nge, bool flush) { - struct kvm_mmu_page *root; - - for_each_tdp_mmu_root_yield_safe(kvm, root, range->slot->as_id, false) - flush =3D zap_gfn_range(kvm, root, range->start, range->end, - range->may_block, flush, false); - - return flush; + return __kvm_tdp_mmu_zap_gfn_range(kvm, range->slot->as_id, range->start, + range->end, range->may_block, flush); } =20 typedef bool (*tdp_handler_t)(struct kvm *kvm, struct tdp_iter *iter, @@ -1221,7 +1233,7 @@ bool kvm_tdp_mmu_wrprot_slot(struct kvm *kvm, =20 lockdep_assert_held_read(&kvm->mmu_lock); =20 - for_each_tdp_mmu_root_yield_safe(kvm, root, slot->as_id, true) + for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id, true) spte_set |=3D wrprot_gfn_range(kvm, root, slot->base_gfn, slot->base_gfn + slot->npages, min_level); =20 @@ -1249,6 +1261,9 @@ static bool clear_dirty_gfn_range(struct kvm *kvm, st= ruct kvm_mmu_page *root, if (tdp_mmu_iter_cond_resched(kvm, &iter, false, true)) continue; =20 + if (!is_shadow_present_pte(iter.old_spte)) + continue; + if (spte_ad_need_write_protect(iter.old_spte)) { if (is_writable_pte(iter.old_spte)) new_spte =3D iter.old_spte & ~PT_WRITABLE_MASK; @@ -1291,7 +1306,7 @@ bool kvm_tdp_mmu_clear_dirty_slot(struct kvm *kvm, =20 lockdep_assert_held_read(&kvm->mmu_lock); =20 - for_each_tdp_mmu_root_yield_safe(kvm, root, slot->as_id, true) + for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id, true) spte_set |=3D clear_dirty_gfn_range(kvm, root, slot->base_gfn, slot->base_gfn + slot->npages); =20 @@ -1416,7 +1431,7 @@ void kvm_tdp_mmu_zap_collapsible_sptes(struct kvm *kv= m, =20 lockdep_assert_held_read(&kvm->mmu_lock); =20 - for_each_tdp_mmu_root_yield_safe(kvm, root, slot->as_id, true) + for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id, true) zap_collapsible_spte_range(kvm, root, slot); } =20 diff --git a/arch/x86/kvm/mmu/tdp_mmu.h b/arch/x86/kvm/mmu/tdp_mmu.h index 3899004a5d91..08c917511fed 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.h +++ b/arch/x86/kvm/mmu/tdp_mmu.h @@ -10,9 +10,6 @@ hpa_t kvm_tdp_mmu_get_vcpu_root_hpa(struct kvm_vcpu *vcpu= ); __must_check static inline bool kvm_tdp_mmu_get_root(struct kvm *kvm, struct kvm_mmu_page *root) { - if (root->role.invalid) - return false; - return refcount_inc_not_zero(&root->tdp_mmu_root_count); } =20 diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index 212af871ca74..72713324f3bf 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -799,7 +799,7 @@ int svm_update_pi_irte(struct kvm *kvm, unsigned int ho= st_irq, { struct kvm_kernel_irq_routing_entry *e; struct kvm_irq_routing_table *irq_rt; - int idx, ret =3D -EINVAL; + int idx, ret =3D 0; =20 if (!kvm_arch_has_assigned_device(kvm) || !irq_remapping_cap(IRQ_POSTING_CAP)) @@ -810,7 +810,13 @@ int svm_update_pi_irte(struct kvm *kvm, unsigned int h= ost_irq, =20 idx =3D srcu_read_lock(&kvm->irq_srcu); irq_rt =3D srcu_dereference(kvm->irq_routing, &kvm->irq_srcu); - WARN_ON(guest_irq >=3D irq_rt->nr_rt_entries); + + if (guest_irq >=3D irq_rt->nr_rt_entries || + hlist_empty(&irq_rt->map[guest_irq])) { + pr_warn_once("no route for guest_irq %u/%u (broken user space?)\n", + guest_irq, irq_rt->nr_rt_entries); + goto out; + } =20 hlist_for_each_entry(e, &irq_rt->map[guest_irq], link) { struct vcpu_data vcpu_info; diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index be2883141220..20a5d3abaeda 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -2352,7 +2352,7 @@ static void sev_es_sync_from_ghcb(struct vcpu_svm *sv= m) memset(ghcb->save.valid_bitmap, 0, sizeof(ghcb->save.valid_bitmap)); } =20 -static bool sev_es_validate_vmgexit(struct vcpu_svm *svm) +static int sev_es_validate_vmgexit(struct vcpu_svm *svm) { struct kvm_vcpu *vcpu; struct ghcb *ghcb; @@ -2457,7 +2457,7 @@ static bool sev_es_validate_vmgexit(struct vcpu_svm *= svm) goto vmgexit_err; } =20 - return true; + return 0; =20 vmgexit_err: vcpu =3D &svm->vcpu; @@ -2480,7 +2480,8 @@ static bool sev_es_validate_vmgexit(struct vcpu_svm *= svm) ghcb_set_sw_exit_info_1(ghcb, 2); ghcb_set_sw_exit_info_2(ghcb, reason); =20 - return false; + /* Resume the guest to "return" the error code. */ + return 1; } =20 void sev_es_unmap_ghcb(struct vcpu_svm *svm) @@ -2539,7 +2540,7 @@ void pre_sev_run(struct vcpu_svm *svm, int cpu) } =20 #define GHCB_SCRATCH_AREA_LIMIT (16ULL * PAGE_SIZE) -static bool setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len) +static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len) { struct vmcb_control_area *control =3D &svm->vmcb->control; struct ghcb *ghcb =3D svm->sev_es.ghcb; @@ -2592,14 +2593,14 @@ static bool setup_vmgexit_scratch(struct vcpu_svm *= svm, bool sync, u64 len) } scratch_va =3D kvzalloc(len, GFP_KERNEL_ACCOUNT); if (!scratch_va) - goto e_scratch; + return -ENOMEM; =20 if (kvm_read_guest(svm->vcpu.kvm, scratch_gpa_beg, scratch_va, len)) { /* Unable to copy scratch area from guest */ pr_err("vmgexit: kvm_read_guest for scratch area failed\n"); =20 kvfree(scratch_va); - goto e_scratch; + return -EFAULT; } =20 /* @@ -2615,13 +2616,13 @@ static bool setup_vmgexit_scratch(struct vcpu_svm *= svm, bool sync, u64 len) svm->sev_es.ghcb_sa =3D scratch_va; svm->sev_es.ghcb_sa_len =3D len; =20 - return true; + return 0; =20 e_scratch: ghcb_set_sw_exit_info_1(ghcb, 2); ghcb_set_sw_exit_info_2(ghcb, GHCB_ERR_INVALID_SCRATCH_AREA); =20 - return false; + return 1; } =20 static void set_ghcb_msr_bits(struct vcpu_svm *svm, u64 value, u64 mask, @@ -2759,17 +2760,18 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) =20 exit_code =3D ghcb_get_sw_exit_code(ghcb); =20 - if (!sev_es_validate_vmgexit(svm)) - return 1; + ret =3D sev_es_validate_vmgexit(svm); + if (ret) + return ret; =20 sev_es_sync_from_ghcb(svm); ghcb_set_sw_exit_info_1(ghcb, 0); ghcb_set_sw_exit_info_2(ghcb, 0); =20 - ret =3D 1; switch (exit_code) { case SVM_VMGEXIT_MMIO_READ: - if (!setup_vmgexit_scratch(svm, true, control->exit_info_2)) + ret =3D setup_vmgexit_scratch(svm, true, control->exit_info_2); + if (ret) break; =20 ret =3D kvm_sev_es_mmio_read(vcpu, @@ -2778,7 +2780,8 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) svm->sev_es.ghcb_sa); break; case SVM_VMGEXIT_MMIO_WRITE: - if (!setup_vmgexit_scratch(svm, false, control->exit_info_2)) + ret =3D setup_vmgexit_scratch(svm, false, control->exit_info_2); + if (ret) break; =20 ret =3D kvm_sev_es_mmio_write(vcpu, @@ -2811,6 +2814,7 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) ghcb_set_sw_exit_info_2(ghcb, GHCB_ERR_INVALID_INPUT); } =20 + ret =3D 1; break; } case SVM_VMGEXIT_UNSUPPORTED_EVENT: @@ -2830,6 +2834,7 @@ int sev_es_string_io(struct vcpu_svm *svm, int size, = unsigned int port, int in) { int count; int bytes; + int r; =20 if (svm->vmcb->control.exit_info_2 > INT_MAX) return -EINVAL; @@ -2838,8 +2843,9 @@ int sev_es_string_io(struct vcpu_svm *svm, int size, = unsigned int port, int in) if (unlikely(check_mul_overflow(count, size, &bytes))) return -EINVAL; =20 - if (!setup_vmgexit_scratch(svm, in, bytes)) - return 1; + r =3D setup_vmgexit_scratch(svm, in, bytes); + if (r) + return r; =20 return kvm_sev_es_string_io(&svm->vcpu, size, port, svm->sev_es.ghcb_sa, count, in); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index e8f495b9ae10..ff181a6c1005 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1614,8 +1614,7 @@ static int set_efer(struct kvm_vcpu *vcpu, struct msr= _data *msr_info) return r; } =20 - /* Update reserved bits */ - if ((efer ^ old_efer) & EFER_NX) + if ((efer ^ old_efer) & KVM_MMU_EFER_ROLE_BITS) kvm_mmu_reset_context(vcpu); =20 return 0; diff --git a/arch/x86/xen/pmu.c b/arch/x86/xen/pmu.c index e13b0b49fcdf..d7249f4c90f1 100644 --- a/arch/x86/xen/pmu.c +++ b/arch/x86/xen/pmu.c @@ -512,10 +512,7 @@ irqreturn_t xen_pmu_irq_handler(int irq, void *dev_id) return ret; } =20 -bool is_xen_pmu(int cpu) -{ - return (get_xenpmu_data() !=3D NULL); -} +bool is_xen_pmu; =20 void xen_pmu_init(int cpu) { @@ -526,7 +523,7 @@ void xen_pmu_init(int cpu) =20 BUILD_BUG_ON(sizeof(struct xen_pmu_data) > PAGE_SIZE); =20 - if (xen_hvm_domain()) + if (xen_hvm_domain() || (cpu !=3D 0 && !is_xen_pmu)) return; =20 xenpmu_data =3D (struct xen_pmu_data *)get_zeroed_page(GFP_KERNEL); @@ -547,7 +544,8 @@ void xen_pmu_init(int cpu) per_cpu(xenpmu_shared, cpu).xenpmu_data =3D xenpmu_data; per_cpu(xenpmu_shared, cpu).flags =3D 0; =20 - if (cpu =3D=3D 0) { + if (!is_xen_pmu) { + is_xen_pmu =3D true; perf_register_guest_info_callbacks(&xen_guest_cbs); xen_pmu_arch_init(); } diff --git a/arch/x86/xen/pmu.h b/arch/x86/xen/pmu.h index 0e83a160589b..65c58894fc79 100644 --- a/arch/x86/xen/pmu.h +++ b/arch/x86/xen/pmu.h @@ -4,6 +4,8 @@ =20 #include =20 +extern bool is_xen_pmu; + irqreturn_t xen_pmu_irq_handler(int irq, void *dev_id); #ifdef CONFIG_XEN_HAVE_VPMU void xen_pmu_init(int cpu); @@ -12,7 +14,6 @@ void xen_pmu_finish(int cpu); static inline void xen_pmu_init(int cpu) {} static inline void xen_pmu_finish(int cpu) {} #endif -bool is_xen_pmu(int cpu); bool pmu_msr_read(unsigned int msr, uint64_t *val, int *err); bool pmu_msr_write(unsigned int msr, uint32_t low, uint32_t high, int *err= ); int pmu_apic_update(uint32_t reg); diff --git a/arch/x86/xen/smp_pv.c b/arch/x86/xen/smp_pv.c index 4a6019238ee7..688aa8b6ae29 100644 --- a/arch/x86/xen/smp_pv.c +++ b/arch/x86/xen/smp_pv.c @@ -129,7 +129,7 @@ int xen_smp_intr_init_pv(unsigned int cpu) per_cpu(xen_irq_work, cpu).irq =3D rc; per_cpu(xen_irq_work, cpu).name =3D callfunc_name; =20 - if (is_xen_pmu(cpu)) { + if (is_xen_pmu) { pmu_name =3D kasprintf(GFP_KERNEL, "pmu%d", cpu); rc =3D bind_virq_to_irqhandler(VIRQ_XENPMU, cpu, xen_pmu_irq_handler, diff --git a/arch/xtensa/include/asm/pgtable.h b/arch/xtensa/include/asm/pg= table.h index bd5aeb795567..a63eca126657 100644 --- a/arch/xtensa/include/asm/pgtable.h +++ b/arch/xtensa/include/asm/pgtable.h @@ -411,6 +411,10 @@ extern void update_mmu_cache(struct vm_area_struct * = vma, =20 typedef pte_t *pte_addr_t; =20 +void update_mmu_tlb(struct vm_area_struct *vma, + unsigned long address, pte_t *ptep); +#define __HAVE_ARCH_UPDATE_MMU_TLB + #endif /* !defined (__ASSEMBLY__) */ =20 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/= processor.h index 37d3e9887fe7..d68987d703e7 100644 --- a/arch/xtensa/include/asm/processor.h +++ b/arch/xtensa/include/asm/processor.h @@ -246,8 +246,8 @@ extern unsigned long __get_wchan(struct task_struct *p); =20 #define xtensa_set_sr(x, sr) \ ({ \ - unsigned int v =3D (unsigned int)(x); \ - __asm__ __volatile__ ("wsr %0, "__stringify(sr) :: "a"(v)); \ + __asm__ __volatile__ ("wsr %0, "__stringify(sr) :: \ + "a"((unsigned int)(x))); \ }) =20 #define xtensa_get_sr(sr) \ diff --git a/arch/xtensa/kernel/jump_label.c b/arch/xtensa/kernel/jump_labe= l.c index 61cf6497a646..0dde21e0d3de 100644 --- a/arch/xtensa/kernel/jump_label.c +++ b/arch/xtensa/kernel/jump_label.c @@ -61,7 +61,7 @@ static void patch_text(unsigned long addr, const void *da= ta, size_t sz) .data =3D data, }; stop_machine_cpuslocked(patch_text_stop_machine, - &patch, NULL); + &patch, cpu_online_mask); } else { unsigned long flags; =20 diff --git a/arch/xtensa/kernel/mxhead.S b/arch/xtensa/kernel/mxhead.S index 9f3843742726..b702c0908b1f 100644 --- a/arch/xtensa/kernel/mxhead.S +++ b/arch/xtensa/kernel/mxhead.S @@ -37,11 +37,13 @@ _SetupOCD: * xt-gdb to single step via DEBUG exceptions received directly * by ocd. */ +#if XCHAL_HAVE_WINDOWED movi a1, 1 movi a0, 0 wsr a1, windowstart wsr a0, windowbase rsync +#endif =20 movi a1, LOCKLEVEL wsr a1, ps diff --git a/arch/xtensa/mm/tlb.c b/arch/xtensa/mm/tlb.c index f436cf2efd8b..27a477dae232 100644 --- a/arch/xtensa/mm/tlb.c +++ b/arch/xtensa/mm/tlb.c @@ -162,6 +162,12 @@ void local_flush_tlb_kernel_range(unsigned long start,= unsigned long end) } } =20 +void update_mmu_tlb(struct vm_area_struct *vma, + unsigned long address, pte_t *ptep) +{ + local_flush_tlb_page(vma, address); +} + #ifdef CONFIG_DEBUG_TLB_SANITY =20 static unsigned get_pte_for_vaddr(unsigned vaddr) diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c index 24a5c5329bcd..809bc612d96b 100644 --- a/block/bfq-cgroup.c +++ b/block/bfq-cgroup.c @@ -646,6 +646,12 @@ void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_q= ueue *bfqq, { struct bfq_entity *entity =3D &bfqq->entity; =20 + /* + * oom_bfqq is not allowed to move, oom_bfqq will hold ref to root_group + * until elevator exit. + */ + if (bfqq =3D=3D &bfqd->oom_bfqq) + return; /* * Get extra reference to prevent bfqq from being freed in * next possible expire or deactivate. diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c index 8c0950c9a1a2..342e927f213b 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c @@ -2662,6 +2662,15 @@ bfq_setup_merge(struct bfq_queue *bfqq, struct bfq_q= ueue *new_bfqq) * are likely to increase the throughput. */ bfqq->new_bfqq =3D new_bfqq; + /* + * The above assignment schedules the following redirections: + * each time some I/O for bfqq arrives, the process that + * generated that I/O is disassociated from bfqq and + * associated with new_bfqq. Here we increases new_bfqq->ref + * in advance, adding the number of processes that are + * expected to be associated with new_bfqq as they happen to + * issue I/O. + */ new_bfqq->ref +=3D process_refs; return new_bfqq; } @@ -2724,6 +2733,10 @@ bfq_setup_cooperator(struct bfq_data *bfqd, struct b= fq_queue *bfqq, { struct bfq_queue *in_service_bfqq, *new_bfqq; =20 + /* if a merge has already been setup, then proceed with that first */ + if (bfqq->new_bfqq) + return bfqq->new_bfqq; + /* * Check delayed stable merge for rotational or non-queueing * devs. For this branch to be executed, bfqq must not be @@ -2825,9 +2838,6 @@ bfq_setup_cooperator(struct bfq_data *bfqd, struct bf= q_queue *bfqq, if (bfq_too_late_for_merging(bfqq)) return NULL; =20 - if (bfqq->new_bfqq) - return bfqq->new_bfqq; - if (!io_struct || unlikely(bfqq =3D=3D &bfqd->oom_bfqq)) return NULL; =20 @@ -5061,7 +5071,7 @@ static struct request *bfq_dispatch_request(struct bl= k_mq_hw_ctx *hctx) struct bfq_data *bfqd =3D hctx->queue->elevator->elevator_data; struct request *rq; struct bfq_queue *in_serv_queue; - bool waiting_rq, idle_timer_disabled; + bool waiting_rq, idle_timer_disabled =3D false; =20 spin_lock_irq(&bfqd->lock); =20 @@ -5069,14 +5079,15 @@ static struct request *bfq_dispatch_request(struct = blk_mq_hw_ctx *hctx) waiting_rq =3D in_serv_queue && bfq_bfqq_wait_request(in_serv_queue); =20 rq =3D __bfq_dispatch_request(hctx); - - idle_timer_disabled =3D - waiting_rq && !bfq_bfqq_wait_request(in_serv_queue); + if (in_serv_queue =3D=3D bfqd->in_service_queue) { + idle_timer_disabled =3D + waiting_rq && !bfq_bfqq_wait_request(in_serv_queue); + } =20 spin_unlock_irq(&bfqd->lock); - - bfq_update_dispatch_stats(hctx->queue, rq, in_serv_queue, - idle_timer_disabled); + bfq_update_dispatch_stats(hctx->queue, rq, + idle_timer_disabled ? in_serv_queue : NULL, + idle_timer_disabled); =20 return rq; } diff --git a/block/bfq-wf2q.c b/block/bfq-wf2q.c index b74cc0da118e..709b901de3ca 100644 --- a/block/bfq-wf2q.c +++ b/block/bfq-wf2q.c @@ -519,7 +519,7 @@ unsigned short bfq_ioprio_to_weight(int ioprio) static unsigned short bfq_weight_to_ioprio(int weight) { return max_t(int, 0, - IOPRIO_NR_LEVELS * BFQ_WEIGHT_CONVERSION_COEFF - weight); + IOPRIO_NR_LEVELS - weight / BFQ_WEIGHT_CONVERSION_COEFF); } =20 static void bfq_get_entity(struct bfq_entity *entity) diff --git a/block/bio.c b/block/bio.c index 99cad261ec53..b49c6f87e638 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1462,8 +1462,7 @@ void bio_endio(struct bio *bio) if (!bio_integrity_endio(bio)) return; =20 - if (bio->bi_bdev && bio_flagged(bio, BIO_TRACKED)) - rq_qos_done_bio(bdev_get_queue(bio->bi_bdev), bio); + rq_qos_done_bio(bio); =20 if (bio->bi_bdev && bio_flagged(bio, BIO_TRACE_COMPLETION)) { trace_block_bio_complete(bdev_get_queue(bio->bi_bdev), bio); diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 663aabfeba18..f896f4982665 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -856,11 +856,11 @@ static void blkcg_fill_root_iostats(void) blk_queue_root_blkg(bdev_get_queue(bdev)); struct blkg_iostat tmp; int cpu; + unsigned long flags; =20 memset(&tmp, 0, sizeof(tmp)); for_each_possible_cpu(cpu) { struct disk_stats *cpu_dkstats; - unsigned long flags; =20 cpu_dkstats =3D per_cpu_ptr(bdev->bd_stats, cpu); tmp.ios[BLKG_IOSTAT_READ] +=3D @@ -876,11 +876,11 @@ static void blkcg_fill_root_iostats(void) cpu_dkstats->sectors[STAT_WRITE] << 9; tmp.bytes[BLKG_IOSTAT_DISCARD] +=3D cpu_dkstats->sectors[STAT_DISCARD] << 9; - - flags =3D u64_stats_update_begin_irqsave(&blkg->iostat.sync); - blkg_iostat_set(&blkg->iostat.cur, &tmp); - u64_stats_update_end_irqrestore(&blkg->iostat.sync, flags); } + + flags =3D u64_stats_update_begin_irqsave(&blkg->iostat.sync); + blkg_iostat_set(&blkg->iostat.cur, &tmp); + u64_stats_update_end_irqrestore(&blkg->iostat.sync, flags); } } =20 diff --git a/block/blk-iolatency.c b/block/blk-iolatency.c index 6593c7123b97..24d70e0555dd 100644 --- a/block/blk-iolatency.c +++ b/block/blk-iolatency.c @@ -598,7 +598,7 @@ static void blkcg_iolatency_done_bio(struct rq_qos *rqo= s, struct bio *bio) int inflight =3D 0; =20 blkg =3D bio->bi_blkg; - if (!blkg || !bio_flagged(bio, BIO_TRACKED)) + if (!blkg || !bio_flagged(bio, BIO_QOS_THROTTLED)) return; =20 iolat =3D blkg_to_lat(bio->bi_blkg); diff --git a/block/blk-merge.c b/block/blk-merge.c index 893c1a60b701..09bf679dc132 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -8,6 +8,7 @@ #include #include #include +#include =20 #include =20 @@ -366,8 +367,6 @@ void __blk_queue_split(struct request_queue *q, struct = bio **bio, trace_block_split(split, (*bio)->bi_iter.bi_sector); submit_bio_noacct(*bio); *bio =3D split; - - blk_throtl_charge_bio_split(*bio); } } =20 @@ -598,6 +597,9 @@ static inline unsigned int blk_rq_get_max_sectors(struc= t request *rq, static inline int ll_new_hw_segment(struct request *req, struct bio *bio, unsigned int nr_phys_segs) { + if (!blk_cgroup_mergeable(req, bio)) + goto no_merge; + if (blk_integrity_merge_bio(req->q, req, bio) =3D=3D false) goto no_merge; =20 @@ -694,6 +696,9 @@ static int ll_merge_requests_fn(struct request_queue *q= , struct request *req, if (total_phys_segments > blk_rq_get_max_segments(req)) return 0; =20 + if (!blk_cgroup_mergeable(req, next->bio)) + return 0; + if (blk_integrity_merge_rq(q, req, next) =3D=3D false) return 0; =20 @@ -907,6 +912,10 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *b= io) if (rq->rq_disk !=3D bio->bi_bdev->bd_disk) return false; =20 + /* don't merge across cgroup boundaries */ + if (!blk_cgroup_mergeable(rq, bio)) + return false; + /* only merge integrity protected bio into ditto rq */ if (blk_integrity_merge_bio(rq->q, rq, bio) =3D=3D false) return false; @@ -1093,18 +1102,21 @@ bool blk_attempt_plug_merge(struct request_queue *q= , struct bio *bio, if (!plug || rq_list_empty(plug->mq_list)) return false; =20 - /* check the previously added entry for a quick merge attempt */ - rq =3D rq_list_peek(&plug->mq_list); - if (rq->q =3D=3D q) { + rq_list_for_each(&plug->mq_list, rq) { + if (rq->q =3D=3D q) { + *same_queue_rq =3D true; + if (blk_attempt_bio_merge(q, rq, bio, nr_segs, false) =3D=3D + BIO_MERGE_OK) + return true; + break; + } + /* - * Only blk-mq multiple hardware queues case checks the rq in - * the same queue, there should be only one such rq in a queue + * Only keep iterating plug list for merges if we have multiple + * queues */ - *same_queue_rq =3D true; - - if (blk_attempt_bio_merge(q, rq, bio, nr_segs, false) =3D=3D - BIO_MERGE_OK) - return true; + if (!plug->multiple_queues) + break; } return false; } diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c index ba21449439cc..9fb68aafe6f4 100644 --- a/block/blk-mq-sched.c +++ b/block/blk-mq-sched.c @@ -206,11 +206,18 @@ static int __blk_mq_do_dispatch_sched(struct blk_mq_h= w_ctx *hctx) =20 static int blk_mq_do_dispatch_sched(struct blk_mq_hw_ctx *hctx) { + unsigned long end =3D jiffies + HZ; int ret; =20 do { ret =3D __blk_mq_do_dispatch_sched(hctx); - } while (ret =3D=3D 1); + if (ret !=3D 1) + break; + if (need_resched() || time_is_before_jiffies(end)) { + blk_mq_delay_run_hw_queue(hctx, 0); + break; + } + } while (1); =20 return ret; } diff --git a/block/blk-mq.c b/block/blk-mq.c index 8874a63ae952..8ef88aa1efbe 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -2244,13 +2244,35 @@ static void blk_mq_plug_issue_direct(struct blk_plu= g *plug, bool from_schedule) blk_mq_commit_rqs(hctx, &queued, from_schedule); } =20 -void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule) +static void blk_mq_dispatch_plug_list(struct blk_plug *plug, bool from_sch= ed) { - struct blk_mq_hw_ctx *this_hctx; - struct blk_mq_ctx *this_ctx; - unsigned int depth; + struct blk_mq_hw_ctx *this_hctx =3D NULL; + struct blk_mq_ctx *this_ctx =3D NULL; + struct request *requeue_list =3D NULL; + unsigned int depth =3D 0; LIST_HEAD(list); =20 + do { + struct request *rq =3D rq_list_pop(&plug->mq_list); + + if (!this_hctx) { + this_hctx =3D rq->mq_hctx; + this_ctx =3D rq->mq_ctx; + } else if (this_hctx !=3D rq->mq_hctx || this_ctx !=3D rq->mq_ctx) { + rq_list_add(&requeue_list, rq); + continue; + } + list_add_tail(&rq->queuelist, &list); + depth++; + } while (!rq_list_empty(plug->mq_list)); + + plug->mq_list =3D requeue_list; + trace_block_unplug(this_hctx->queue, depth, !from_sched); + blk_mq_sched_insert_requests(this_hctx, this_ctx, &list, from_sched); +} + +void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule) +{ if (rq_list_empty(plug->mq_list)) return; plug->rq_count =3D 0; @@ -2261,37 +2283,9 @@ void blk_mq_flush_plug_list(struct blk_plug *plug, b= ool from_schedule) return; } =20 - this_hctx =3D NULL; - this_ctx =3D NULL; - depth =3D 0; do { - struct request *rq; - - rq =3D rq_list_pop(&plug->mq_list); - - if (!this_hctx) { - this_hctx =3D rq->mq_hctx; - this_ctx =3D rq->mq_ctx; - } else if (this_hctx !=3D rq->mq_hctx || this_ctx !=3D rq->mq_ctx) { - trace_block_unplug(this_hctx->queue, depth, - !from_schedule); - blk_mq_sched_insert_requests(this_hctx, this_ctx, - &list, from_schedule); - depth =3D 0; - this_hctx =3D rq->mq_hctx; - this_ctx =3D rq->mq_ctx; - - } - - list_add(&rq->queuelist, &list); - depth++; + blk_mq_dispatch_plug_list(plug, from_schedule); } while (!rq_list_empty(plug->mq_list)); - - if (!list_empty(&list)) { - trace_block_unplug(this_hctx->queue, depth, !from_schedule); - blk_mq_sched_insert_requests(this_hctx, this_ctx, &list, - from_schedule); - } } =20 static void blk_mq_bio_to_request(struct request *rq, struct bio *bio, diff --git a/block/blk-rq-qos.h b/block/blk-rq-qos.h index 3cfbc8668cba..68267007da1c 100644 --- a/block/blk-rq-qos.h +++ b/block/blk-rq-qos.h @@ -177,20 +177,20 @@ static inline void rq_qos_requeue(struct request_queu= e *q, struct request *rq) __rq_qos_requeue(q->rq_qos, rq); } =20 -static inline void rq_qos_done_bio(struct request_queue *q, struct bio *bi= o) +static inline void rq_qos_done_bio(struct bio *bio) { - if (q->rq_qos) - __rq_qos_done_bio(q->rq_qos, bio); + if (bio->bi_bdev && (bio_flagged(bio, BIO_QOS_THROTTLED) || + bio_flagged(bio, BIO_QOS_MERGED))) { + struct request_queue *q =3D bdev_get_queue(bio->bi_bdev); + if (q->rq_qos) + __rq_qos_done_bio(q->rq_qos, bio); + } } =20 static inline void rq_qos_throttle(struct request_queue *q, struct bio *bi= o) { - /* - * BIO_TRACKED lets controllers know that a bio went through the - * normal rq_qos path. - */ if (q->rq_qos) { - bio_set_flag(bio, BIO_TRACKED); + bio_set_flag(bio, BIO_QOS_THROTTLED); __rq_qos_throttle(q->rq_qos, bio); } } @@ -205,8 +205,10 @@ static inline void rq_qos_track(struct request_queue *= q, struct request *rq, static inline void rq_qos_merge(struct request_queue *q, struct request *r= q, struct bio *bio) { - if (q->rq_qos) + if (q->rq_qos) { + bio_set_flag(bio, BIO_QOS_MERGED); __rq_qos_merge(q->rq_qos, rq, bio); + } } =20 static inline void rq_qos_queue_depth_changed(struct request_queue *q) diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index cd75b0f73dc6..2fe8da2a7216 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -949,9 +949,6 @@ void blk_unregister_queue(struct gendisk *disk) */ if (queue_is_mq(q)) blk_mq_unregister_dev(disk_to_dev(disk), q); - - kobject_uevent(&q->kobj, KOBJ_REMOVE); - kobject_del(&q->kobj); blk_trace_remove_sysfs(disk_to_dev(disk)); =20 mutex_lock(&q->sysfs_lock); @@ -959,6 +956,11 @@ void blk_unregister_queue(struct gendisk *disk) elv_unregister_queue(q); disk_unregister_independent_access_ranges(disk); mutex_unlock(&q->sysfs_lock); + + /* Now that we've deleted all child objects, we can delete the queue. */ + kobject_uevent(&q->kobj, KOBJ_REMOVE); + kobject_del(&q->kobj); + mutex_unlock(&q->sysfs_dir_lock); =20 kobject_put(&disk_to_dev(disk)->kobj); diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 39bb6e68a9a2..96573fa4edf2 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -807,7 +807,8 @@ static bool tg_with_in_bps_limit(struct throtl_grp *tg,= struct bio *bio, unsigned long jiffy_elapsed, jiffy_wait, jiffy_elapsed_rnd; unsigned int bio_size =3D throtl_bio_data_size(bio); =20 - if (bps_limit =3D=3D U64_MAX) { + /* no need to throttle if this bio's bytes have been accounted */ + if (bps_limit =3D=3D U64_MAX || bio_flagged(bio, BIO_THROTTLED)) { if (wait) *wait =3D 0; return true; @@ -919,9 +920,12 @@ static void throtl_charge_bio(struct throtl_grp *tg, s= truct bio *bio) unsigned int bio_size =3D throtl_bio_data_size(bio); =20 /* Charge the bio to the group */ - tg->bytes_disp[rw] +=3D bio_size; + if (!bio_flagged(bio, BIO_THROTTLED)) { + tg->bytes_disp[rw] +=3D bio_size; + tg->last_bytes_disp[rw] +=3D bio_size; + } + tg->io_disp[rw]++; - tg->last_bytes_disp[rw] +=3D bio_size; tg->last_io_disp[rw]++; =20 /* diff --git a/block/blk-throttle.h b/block/blk-throttle.h index 175f03abd9e4..cb43f4417d6e 100644 --- a/block/blk-throttle.h +++ b/block/blk-throttle.h @@ -170,8 +170,6 @@ static inline bool blk_throtl_bio(struct bio *bio) { struct throtl_grp *tg =3D blkg_to_tg(bio->bi_blkg); =20 - if (bio_flagged(bio, BIO_THROTTLED)) - return false; if (!tg->has_rules[bio_data_dir(bio)]) return false; =20 diff --git a/block/genhd.c b/block/genhd.c index f6a698f3252b..2a469f774670 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -328,7 +328,7 @@ int blk_alloc_ext_minor(void) { int idx; =20 - idx =3D ida_alloc_range(&ext_devt_ida, 0, NR_EXT_DEVT, GFP_KERNEL); + idx =3D ida_alloc_range(&ext_devt_ida, 0, NR_EXT_DEVT - 1, GFP_KERNEL); if (idx =3D=3D -ENOSPC) return -EBUSY; return idx; diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys= /pkcs7_verify.c index 0b4d07aa8811..f94a1d1ad3a6 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c @@ -174,12 +174,6 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7, pr_devel("Sig %u: Found cert serial match X.509[%u]\n", sinfo->index, certix); =20 - if (strcmp(x509->pub->pkey_algo, sinfo->sig->pkey_algo) !=3D 0) { - pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n", - sinfo->index); - continue; - } - sinfo->signer =3D x509; return 0; } diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/p= ublic_key.c index 4fefb219bfdc..7c9e6be35c30 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c @@ -60,39 +60,83 @@ static void public_key_destroy(void *payload0, void *pa= yload3) } =20 /* - * Determine the crypto algorithm name. + * Given a public_key, and an encoding and hash_algo to be used for signing + * and/or verification with that key, determine the name of the correspond= ing + * akcipher algorithm. Also check that encoding and hash_algo are allowed. */ -static -int software_key_determine_akcipher(const char *encoding, - const char *hash_algo, - const struct public_key *pkey, - char alg_name[CRYPTO_MAX_ALG_NAME]) +static int +software_key_determine_akcipher(const struct public_key *pkey, + const char *encoding, const char *hash_algo, + char alg_name[CRYPTO_MAX_ALG_NAME]) { int n; =20 - if (strcmp(encoding, "pkcs1") =3D=3D 0) { - /* The data wangled by the RSA algorithm is typically padded - * and encoded in some manner, such as EMSA-PKCS1-1_5 [RFC3447 - * sec 8.2]. + if (!encoding) + return -EINVAL; + + if (strcmp(pkey->pkey_algo, "rsa") =3D=3D 0) { + /* + * RSA signatures usually use EMSA-PKCS1-1_5 [RFC3447 sec 8.2]. + */ + if (strcmp(encoding, "pkcs1") =3D=3D 0) { + if (!hash_algo) + n =3D snprintf(alg_name, CRYPTO_MAX_ALG_NAME, + "pkcs1pad(%s)", + pkey->pkey_algo); + else + n =3D snprintf(alg_name, CRYPTO_MAX_ALG_NAME, + "pkcs1pad(%s,%s)", + pkey->pkey_algo, hash_algo); + return n >=3D CRYPTO_MAX_ALG_NAME ? -EINVAL : 0; + } + if (strcmp(encoding, "raw") !=3D 0) + return -EINVAL; + /* + * Raw RSA cannot differentiate between different hash + * algorithms. + */ + if (hash_algo) + return -EINVAL; + } else if (strncmp(pkey->pkey_algo, "ecdsa", 5) =3D=3D 0) { + if (strcmp(encoding, "x962") !=3D 0) + return -EINVAL; + /* + * ECDSA signatures are taken over a raw hash, so they don't + * differentiate between different hash algorithms. That means + * that the verifier should hard-code a specific hash algorithm. + * Unfortunately, in practice ECDSA is used with multiple SHAs, + * so we have to allow all of them and not just one. */ if (!hash_algo) - n =3D snprintf(alg_name, CRYPTO_MAX_ALG_NAME, - "pkcs1pad(%s)", - pkey->pkey_algo); - else - n =3D snprintf(alg_name, CRYPTO_MAX_ALG_NAME, - "pkcs1pad(%s,%s)", - pkey->pkey_algo, hash_algo); - return n >=3D CRYPTO_MAX_ALG_NAME ? -EINVAL : 0; - } - - if (strcmp(encoding, "raw") =3D=3D 0 || - strcmp(encoding, "x962") =3D=3D 0) { - strcpy(alg_name, pkey->pkey_algo); - return 0; + return -EINVAL; + if (strcmp(hash_algo, "sha1") !=3D 0 && + strcmp(hash_algo, "sha224") !=3D 0 && + strcmp(hash_algo, "sha256") !=3D 0 && + strcmp(hash_algo, "sha384") !=3D 0 && + strcmp(hash_algo, "sha512") !=3D 0) + return -EINVAL; + } else if (strcmp(pkey->pkey_algo, "sm2") =3D=3D 0) { + if (strcmp(encoding, "raw") !=3D 0) + return -EINVAL; + if (!hash_algo) + return -EINVAL; + if (strcmp(hash_algo, "sm3") !=3D 0) + return -EINVAL; + } else if (strcmp(pkey->pkey_algo, "ecrdsa") =3D=3D 0) { + if (strcmp(encoding, "raw") !=3D 0) + return -EINVAL; + if (!hash_algo) + return -EINVAL; + if (strcmp(hash_algo, "streebog256") !=3D 0 && + strcmp(hash_algo, "streebog512") !=3D 0) + return -EINVAL; + } else { + /* Unknown public key algorithm */ + return -ENOPKG; } - - return -ENOPKG; + if (strscpy(alg_name, pkey->pkey_algo, CRYPTO_MAX_ALG_NAME) < 0) + return -EINVAL; + return 0; } =20 static u8 *pkey_pack_u32(u8 *dst, u32 val) @@ -113,9 +157,8 @@ static int software_key_query(const struct kernel_pkey_= params *params, u8 *key, *ptr; int ret, len; =20 - ret =3D software_key_determine_akcipher(params->encoding, - params->hash_algo, - pkey, alg_name); + ret =3D software_key_determine_akcipher(pkey, params->encoding, + params->hash_algo, alg_name); if (ret < 0) return ret; =20 @@ -179,9 +222,8 @@ static int software_key_eds_op(struct kernel_pkey_param= s *params, =20 pr_devel("=3D=3D>%s()\n", __func__); =20 - ret =3D software_key_determine_akcipher(params->encoding, - params->hash_algo, - pkey, alg_name); + ret =3D software_key_determine_akcipher(pkey, params->encoding, + params->hash_algo, alg_name); if (ret < 0) return ret; =20 @@ -325,9 +367,23 @@ int public_key_verify_signature(const struct public_ke= y *pkey, BUG_ON(!sig); BUG_ON(!sig->s); =20 - ret =3D software_key_determine_akcipher(sig->encoding, - sig->hash_algo, - pkey, alg_name); + /* + * If the signature specifies a public key algorithm, it *must* match + * the key's actual public key algorithm. + * + * Small exception: ECDSA signatures don't specify the curve, but ECDSA + * keys do. So the strings can mismatch slightly in that case: + * "ecdsa-nist-*" for the key, but "ecdsa" for the signature. + */ + if (sig->pkey_algo) { + if (strcmp(pkey->pkey_algo, sig->pkey_algo) !=3D 0 && + (strncmp(pkey->pkey_algo, "ecdsa-", 6) !=3D 0 || + strcmp(sig->pkey_algo, "ecdsa") !=3D 0)) + return -EKEYREJECTED; + } + + ret =3D software_key_determine_akcipher(pkey, sig->encoding, + sig->hash_algo, alg_name); if (ret < 0) return ret; =20 diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_k= eys/x509_public_key.c index 3d45161b271a..7fd56df8b919 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c @@ -128,12 +128,6 @@ int x509_check_for_self_signed(struct x509_certificate= *cert) goto out; } =20 - ret =3D -EKEYREJECTED; - if (strcmp(cert->pub->pkey_algo, cert->sig->pkey_algo) !=3D 0 && - (strncmp(cert->pub->pkey_algo, "ecdsa-", 6) !=3D 0 || - strcmp(cert->sig->pkey_algo, "ecdsa") !=3D 0)) - goto out; - ret =3D public_key_verify_signature(cert->pub, cert->sig); if (ret < 0) { if (ret =3D=3D -ENOPKG) { diff --git a/crypto/authenc.c b/crypto/authenc.c index 670bf1a01d00..17f674a7cdff 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -253,7 +253,7 @@ static int crypto_authenc_decrypt_tail(struct aead_requ= est *req, dst =3D scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen); =20 skcipher_request_set_tfm(skreq, ctx->enc); - skcipher_request_set_callback(skreq, aead_request_flags(req), + skcipher_request_set_callback(skreq, flags, req->base.complete, req->base.data); skcipher_request_set_crypt(skreq, src, dst, req->cryptlen - authsize, req->iv); diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c index 8ac3e73e8ea6..9d804831c8b3 100644 --- a/crypto/rsa-pkcs1pad.c +++ b/crypto/rsa-pkcs1pad.c @@ -476,6 +476,8 @@ static int pkcs1pad_verify_complete(struct akcipher_req= uest *req, int err) pos++; =20 if (digest_info) { + if (digest_info->size > dst_len - pos) + goto done; if (crypto_memneq(out_buf + pos, digest_info->data, digest_info->size)) goto done; @@ -495,7 +497,7 @@ static int pkcs1pad_verify_complete(struct akcipher_req= uest *req, int err) sg_nents_for_len(req->src, req->src_len + req->dst_len), req_ctx->out_buf + ctx->key_size, - req->dst_len, ctx->key_size); + req->dst_len, req->src_len); /* Do the actual verification step. */ if (memcmp(req_ctx->out_buf + ctx->key_size, out_buf + pos, req->dst_len) !=3D 0) @@ -538,7 +540,7 @@ static int pkcs1pad_verify(struct akcipher_request *req) =20 if (WARN_ON(req->dst) || WARN_ON(!req->dst_len) || - !ctx->key_size || req->src_len < ctx->key_size) + !ctx->key_size || req->src_len !=3D ctx->key_size) return -EINVAL; =20 req_ctx->out_buf =3D kmalloc(ctx->key_size + req->dst_len, GFP_KERNEL); @@ -621,6 +623,11 @@ static int pkcs1pad_create(struct crypto_template *tmp= l, struct rtattr **tb) =20 rsa_alg =3D crypto_spawn_akcipher_alg(&ctx->spawn); =20 + if (strcmp(rsa_alg->base.cra_name, "rsa") !=3D 0) { + err =3D -EINVAL; + goto err_free_inst; + } + err =3D -ENAMETOOLONG; hash_name =3D crypto_attr_alg_name(tb[2]); if (IS_ERR(hash_name)) { diff --git a/crypto/xts.c b/crypto/xts.c index 6c12f30dbdd6..63c85b9e64e0 100644 --- a/crypto/xts.c +++ b/crypto/xts.c @@ -466,3 +466,4 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("XTS block cipher mode"); MODULE_ALIAS_CRYPTO("xts"); MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_SOFTDEP("pre: ecb"); diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index 915c2433463d..e7c30ce06e18 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -169,6 +169,9 @@ acpi_ns_walk_namespace(acpi_object_type type, =20 if (start_node =3D=3D ACPI_ROOT_OBJECT) { start_node =3D acpi_gbl_root_node; + if (!start_node) { + return_ACPI_STATUS(AE_NO_NAMESPACE); + } } =20 /* Null child means "get first node" */ diff --git a/drivers/acpi/apei/bert.c b/drivers/acpi/apei/bert.c index 19e50fcbf4d6..598fd19b65fa 100644 --- a/drivers/acpi/apei/bert.c +++ b/drivers/acpi/apei/bert.c @@ -29,6 +29,7 @@ =20 #undef pr_fmt #define pr_fmt(fmt) "BERT: " fmt +#define ACPI_BERT_PRINT_MAX_LEN 1024 =20 static int bert_disable; =20 @@ -58,8 +59,11 @@ static void __init bert_print_all(struct acpi_bert_regio= n *region, } =20 pr_info_once("Error records from previous boot:\n"); - - cper_estatus_print(KERN_INFO HW_ERR, estatus); + if (region_len < ACPI_BERT_PRINT_MAX_LEN) + cper_estatus_print(KERN_INFO HW_ERR, estatus); + else + pr_info_once("Max print length exceeded, table data is available at:\n" + "/sys/firmware/acpi/tables/data/BERT"); =20 /* * Because the boot error source is "one-time polled" type, @@ -77,7 +81,7 @@ static int __init setup_bert_disable(char *str) { bert_disable =3D 1; =20 - return 0; + return 1; } __setup("bert_disable", setup_bert_disable); =20 diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 242f3c2d5533..698d67cee052 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -891,7 +891,7 @@ EXPORT_SYMBOL_GPL(erst_clear); static int __init setup_erst_disable(char *str) { erst_disable =3D 1; - return 0; + return 1; } =20 __setup("erst_disable", setup_erst_disable); diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 0edc1ed47673..6aef1ee5e1bd 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -224,7 +224,7 @@ static int __init hest_ghes_dev_register(unsigned int g= hes_count) static int __init setup_hest_disable(char *str) { hest_disable =3D HEST_DISABLED; - return 0; + return 1; } =20 __setup("hest_disable", setup_hest_disable); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index dd535b4b9a16..3500744e6862 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -332,21 +332,32 @@ static void acpi_bus_osc_negotiate_platform_control(v= oid) if (ACPI_FAILURE(acpi_run_osc(handle, &context))) return; =20 - kfree(context.ret.pointer); + capbuf_ret =3D context.ret.pointer; + if (context.ret.length <=3D OSC_SUPPORT_DWORD) { + kfree(context.ret.pointer); + return; + } =20 - /* Now run _OSC again with query flag clear */ + /* + * Now run _OSC again with query flag clear and with the caps + * supported by both the OS and the platform. + */ capbuf[OSC_QUERY_DWORD] =3D 0; + capbuf[OSC_SUPPORT_DWORD] =3D capbuf_ret[OSC_SUPPORT_DWORD]; + kfree(context.ret.pointer); =20 if (ACPI_FAILURE(acpi_run_osc(handle, &context))) return; =20 capbuf_ret =3D context.ret.pointer; - osc_sb_apei_support_acked =3D - capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_APEI_SUPPORT; - osc_pc_lpi_support_confirmed =3D - capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_PCLPI_SUPPORT; - osc_sb_native_usb4_support_confirmed =3D - capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_NATIVE_USB4_SUPPORT; + if (context.ret.length > OSC_SUPPORT_DWORD) { + osc_sb_apei_support_acked =3D + capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_APEI_SUPPORT; + osc_pc_lpi_support_confirmed =3D + capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_PCLPI_SUPPORT; + osc_sb_native_usb4_support_confirmed =3D + capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_NATIVE_USB4_SUPPORT; + } =20 kfree(context.ret.pointer); } diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 12a156d8283e..c496604fc945 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -690,6 +690,11 @@ int acpi_cppc_processor_probe(struct acpi_processor *p= r) cpc_obj =3D &out_obj->package.elements[0]; if (cpc_obj->type =3D=3D ACPI_TYPE_INTEGER) { num_ent =3D cpc_obj->integer.value; + if (num_ent <=3D 1) { + pr_debug("Unexpected _CPC NumEntries value (%d) for CPU:%d\n", + num_ent, pr->id); + goto out_free; + } } else { pr_debug("Unexpected entry type(%d) for NumEntries\n", cpc_obj->type); diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 2366f54d8e9c..e8f56448ca01 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -685,7 +685,7 @@ int __acpi_node_get_property_reference(const struct fwn= ode_handle *fwnode, */ if (obj->type =3D=3D ACPI_TYPE_LOCAL_REFERENCE) { if (index) - return -EINVAL; + return -ENOENT; =20 ret =3D acpi_bus_get_device(obj->reference.handle, &device); if (ret) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 6b6630693201..64ce42b6c6b6 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -809,7 +809,7 @@ static int __init save_async_options(char *buf) pr_warn("Too long list of driver names for 'driver_async_probe'!\n"); =20 strlcpy(async_probe_drv_names, buf, ASYNC_DRV_NAMES_MAX_LEN); - return 0; + return 1; } __setup("driver_async_probe=3D", save_async_options); =20 diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 365cd4a7f239..60c38f9cf1a7 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -663,14 +663,16 @@ static int init_memory_block(unsigned long block_id, = unsigned long state, mem->nr_vmemmap_pages =3D nr_vmemmap_pages; INIT_LIST_HEAD(&mem->group_next); =20 + ret =3D register_memory(mem); + if (ret) + return ret; + if (group) { mem->group =3D group; list_add(&mem->group_next, &group->memory_blocks); } =20 - ret =3D register_memory(mem); - - return ret; + return 0; } =20 static int add_memory_block(unsigned long base_section_nr) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 5db704f02e71..7e8039d1884c 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -2058,9 +2058,9 @@ static int genpd_remove(struct generic_pm_domain *gen= pd) kfree(link); } =20 - genpd_debug_remove(genpd); list_del(&genpd->gpd_list_node); genpd_unlock(genpd); + genpd_debug_remove(genpd); cancel_work_sync(&genpd->power_off_work); if (genpd_is_cpu_domain(genpd)) free_cpumask_var(genpd->cpus); diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 04ea92cbd9cf..08c8a69d7b81 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -2018,7 +2018,9 @@ static bool pm_ops_is_empty(const struct dev_pm_ops *= ops) =20 void device_pm_check_callbacks(struct device *dev) { - spin_lock_irq(&dev->power.lock); + unsigned long flags; + + spin_lock_irqsave(&dev->power.lock, flags); dev->power.no_pm_callbacks =3D (!dev->bus || (pm_ops_is_empty(dev->bus->pm) && !dev->bus->suspend && !dev->bus->resume)) && @@ -2027,7 +2029,7 @@ void device_pm_check_callbacks(struct device *dev) (!dev->pm_domain || pm_ops_is_empty(&dev->pm_domain->ops)) && (!dev->driver || (pm_ops_is_empty(dev->driver->pm) && !dev->driver->suspend && !dev->driver->resume)); - spin_unlock_irq(&dev->power.lock); + spin_unlock_irqrestore(&dev->power.lock, flags); } =20 bool dev_pm_skip_suspend(struct device *dev) diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 3235532ae077..8b26f631ebc1 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -180,7 +180,8 @@ void start_new_tl_epoch(struct drbd_connection *connect= ion) void complete_master_bio(struct drbd_device *device, struct bio_and_error *m) { - m->bio->bi_status =3D errno_to_blk_status(m->error); + if (unlikely(m->error)) + m->bio->bi_status =3D errno_to_blk_status(m->error); bio_endio(m->bio); dec_ap_bio(device); } diff --git a/drivers/block/loop.c b/drivers/block/loop.c index fdb4798cb006..5c97dcac2710 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -681,33 +681,33 @@ static ssize_t loop_attr_backing_file_show(struct loo= p_device *lo, char *buf) =20 static ssize_t loop_attr_offset_show(struct loop_device *lo, char *buf) { - return sprintf(buf, "%llu\n", (unsigned long long)lo->lo_offset); + return sysfs_emit(buf, "%llu\n", (unsigned long long)lo->lo_offset); } =20 static ssize_t loop_attr_sizelimit_show(struct loop_device *lo, char *buf) { - return sprintf(buf, "%llu\n", (unsigned long long)lo->lo_sizelimit); + return sysfs_emit(buf, "%llu\n", (unsigned long long)lo->lo_sizelimit); } =20 static ssize_t loop_attr_autoclear_show(struct loop_device *lo, char *buf) { int autoclear =3D (lo->lo_flags & LO_FLAGS_AUTOCLEAR); =20 - return sprintf(buf, "%s\n", autoclear ? "1" : "0"); + return sysfs_emit(buf, "%s\n", autoclear ? "1" : "0"); } =20 static ssize_t loop_attr_partscan_show(struct loop_device *lo, char *buf) { int partscan =3D (lo->lo_flags & LO_FLAGS_PARTSCAN); =20 - return sprintf(buf, "%s\n", partscan ? "1" : "0"); + return sysfs_emit(buf, "%s\n", partscan ? "1" : "0"); } =20 static ssize_t loop_attr_dio_show(struct loop_device *lo, char *buf) { int dio =3D (lo->lo_flags & LO_FLAGS_DIRECT_IO); =20 - return sprintf(buf, "%s\n", dio ? "1" : "0"); + return sysfs_emit(buf, "%s\n", dio ? "1" : "0"); } =20 LOOP_ATTR_RO(backing_file); @@ -1603,6 +1603,7 @@ struct compat_loop_info { compat_ulong_t lo_inode; /* ioctl r/o */ compat_dev_t lo_rdevice; /* ioctl r/o */ compat_int_t lo_offset; + compat_int_t lo_encrypt_type; /* obsolete, ignored */ compat_int_t lo_encrypt_key_size; /* ioctl w/o */ compat_int_t lo_flags; /* ioctl r/o */ char lo_name[LO_NAME_SIZE]; diff --git a/drivers/block/n64cart.c b/drivers/block/n64cart.c index 78282f01f581..ef1c9e2e7098 100644 --- a/drivers/block/n64cart.c +++ b/drivers/block/n64cart.c @@ -88,7 +88,7 @@ static void n64cart_submit_bio(struct bio *bio) { struct bio_vec bvec; struct bvec_iter iter; - struct device *dev =3D bio->bi_disk->private_data; + struct device *dev =3D bio->bi_bdev->bd_disk->private_data; u32 pos =3D bio->bi_iter.bi_sector << SECTOR_SHIFT; =20 bio_for_each_segment(bvec, bio, iter) { diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 851a0c9b8fae..a224e5337ef8 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -2426,10 +2426,15 @@ static int btintel_setup_combined(struct hci_dev *h= dev) =20 /* Apply the device specific HCI quirks * - * WBS for SdP - SdP and Stp have a same hw_varaint but - * different fw_variant + * WBS for SdP - For the Legacy ROM products, only SdP + * supports the WBS. But the version information is not + * enough to use here because the StP2 and SdP have same + * hw_variant and fw_variant. So, this flag is set by + * the transport driver (btusb) based on the HW info + * (idProduct) */ - if (ver.hw_variant =3D=3D 0x08 && ver.fw_variant =3D=3D 0x22) + if (!btintel_test_flag(hdev, + INTEL_ROM_LEGACY_NO_WBS_SUPPORT)) set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); =20 diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index c9b24e9299e2..e0060e58573c 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -152,6 +152,7 @@ enum { INTEL_BROKEN_INITIAL_NCMD, INTEL_BROKEN_SHUTDOWN_LED, INTEL_ROM_LEGACY, + INTEL_ROM_LEGACY_NO_WBS_SUPPORT, =20 __INTEL_NUM_FLAGS, }; diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index 1cbdeca1fdc4..ff1f5dfbb6db 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -981,6 +981,8 @@ static int btmtksdio_probe(struct sdio_func *func, hdev->manufacturer =3D 70; set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks); =20 + sdio_set_drvdata(func, bdev); + err =3D hci_register_dev(hdev); if (err < 0) { dev_err(&func->dev, "Can't register HCI device\n"); @@ -988,8 +990,6 @@ static int btmtksdio_probe(struct sdio_func *func, return err; } =20 - sdio_set_drvdata(func, bdev); - /* pm_runtime_enable would be done after the firmware is being * downloaded because the core layer probably already enables * runtime PM for this func such as the case host->caps & diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index c1f1237ddc76..8bb67c56eb7d 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -61,6 +61,7 @@ static struct usb_driver btusb_driver; #define BTUSB_QCA_WCN6855 0x1000000 #define BTUSB_INTEL_BROKEN_SHUTDOWN_LED 0x2000000 #define BTUSB_INTEL_BROKEN_INITIAL_NCMD 0x4000000 +#define BTUSB_INTEL_NO_WBS_SUPPORT 0x8000000 =20 static const struct usb_device_id btusb_table[] =3D { /* Generic Bluetooth USB device */ @@ -384,9 +385,11 @@ static const struct usb_device_id blacklist_table[] = =3D { { USB_DEVICE(0x8087, 0x0033), .driver_info =3D BTUSB_INTEL_COMBINED }, { USB_DEVICE(0x8087, 0x07da), .driver_info =3D BTUSB_CSR }, { USB_DEVICE(0x8087, 0x07dc), .driver_info =3D BTUSB_INTEL_COMBINED | + BTUSB_INTEL_NO_WBS_SUPPORT | BTUSB_INTEL_BROKEN_INITIAL_NCMD | BTUSB_INTEL_BROKEN_SHUTDOWN_LED }, { USB_DEVICE(0x8087, 0x0a2a), .driver_info =3D BTUSB_INTEL_COMBINED | + BTUSB_INTEL_NO_WBS_SUPPORT | BTUSB_INTEL_BROKEN_SHUTDOWN_LED }, { USB_DEVICE(0x8087, 0x0a2b), .driver_info =3D BTUSB_INTEL_COMBINED }, { USB_DEVICE(0x8087, 0x0aa7), .driver_info =3D BTUSB_INTEL_COMBINED | @@ -3902,6 +3905,9 @@ static int btusb_probe(struct usb_interface *intf, hdev->send =3D btusb_send_frame_intel; hdev->cmd_timeout =3D btusb_intel_cmd_timeout; =20 + if (id->driver_info & BTUSB_INTEL_NO_WBS_SUPPORT) + btintel_set_flag(hdev, INTEL_ROM_LEGACY_NO_WBS_SUPPORT); + if (id->driver_info & BTUSB_INTEL_BROKEN_INITIAL_NCMD) btintel_set_flag(hdev, INTEL_BROKEN_INITIAL_NCMD); =20 diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 34286ffe0568..7ac6908a4dfb 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -629,9 +629,11 @@ static int h5_enqueue(struct hci_uart *hu, struct sk_b= uff *skb) break; } =20 - pm_runtime_get_sync(&hu->serdev->dev); - pm_runtime_mark_last_busy(&hu->serdev->dev); - pm_runtime_put_autosuspend(&hu->serdev->dev); + if (hu->serdev) { + pm_runtime_get_sync(&hu->serdev->dev); + pm_runtime_mark_last_busy(&hu->serdev->dev); + pm_runtime_put_autosuspend(&hu->serdev->dev); + } =20 return 0; } diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c index 3b00d82d36cf..4cda890ce647 100644 --- a/drivers/bluetooth/hci_serdev.c +++ b/drivers/bluetooth/hci_serdev.c @@ -305,6 +305,8 @@ int hci_uart_register_device(struct hci_uart *hu, if (err) return err; =20 + percpu_init_rwsem(&hu->proto_lock); + err =3D p->open(hu); if (err) goto err_open; @@ -327,7 +329,6 @@ int hci_uart_register_device(struct hci_uart *hu, =20 INIT_WORK(&hu->init_ready, hci_uart_init_work); INIT_WORK(&hu->write_work, hci_uart_write_work); - percpu_init_rwsem(&hu->proto_lock); =20 /* Only when vendor specific setup callback is provided, consider * the manufacturer information valid. This avoids filling in the diff --git a/drivers/bus/mhi/core/debugfs.c b/drivers/bus/mhi/core/debugfs.c index 858d7516410b..d818586c229d 100644 --- a/drivers/bus/mhi/core/debugfs.c +++ b/drivers/bus/mhi/core/debugfs.c @@ -60,16 +60,16 @@ static int mhi_debugfs_events_show(struct seq_file *m, = void *d) } =20 seq_printf(m, "Index: %d intmod count: %lu time: %lu", - i, (er_ctxt->intmod & EV_CTX_INTMODC_MASK) >> + i, (le32_to_cpu(er_ctxt->intmod) & EV_CTX_INTMODC_MASK) >> EV_CTX_INTMODC_SHIFT, - (er_ctxt->intmod & EV_CTX_INTMODT_MASK) >> + (le32_to_cpu(er_ctxt->intmod) & EV_CTX_INTMODT_MASK) >> EV_CTX_INTMODT_SHIFT); =20 - seq_printf(m, " base: 0x%0llx len: 0x%llx", er_ctxt->rbase, - er_ctxt->rlen); + seq_printf(m, " base: 0x%0llx len: 0x%llx", le64_to_cpu(er_ctxt->rbase), + le64_to_cpu(er_ctxt->rlen)); =20 - seq_printf(m, " rp: 0x%llx wp: 0x%llx", er_ctxt->rp, - er_ctxt->wp); + seq_printf(m, " rp: 0x%llx wp: 0x%llx", le64_to_cpu(er_ctxt->rp), + le64_to_cpu(er_ctxt->wp)); =20 seq_printf(m, " local rp: 0x%pK db: 0x%pad\n", ring->rp, &mhi_event->db_cfg.db_val); @@ -106,18 +106,18 @@ static int mhi_debugfs_channels_show(struct seq_file = *m, void *d) =20 seq_printf(m, "%s(%u) state: 0x%lx brstmode: 0x%lx pollcfg: 0x%lx", - mhi_chan->name, mhi_chan->chan, (chan_ctxt->chcfg & + mhi_chan->name, mhi_chan->chan, (le32_to_cpu(chan_ctxt->chcfg) & CHAN_CTX_CHSTATE_MASK) >> CHAN_CTX_CHSTATE_SHIFT, - (chan_ctxt->chcfg & CHAN_CTX_BRSTMODE_MASK) >> - CHAN_CTX_BRSTMODE_SHIFT, (chan_ctxt->chcfg & + (le32_to_cpu(chan_ctxt->chcfg) & CHAN_CTX_BRSTMODE_MASK) >> + CHAN_CTX_BRSTMODE_SHIFT, (le32_to_cpu(chan_ctxt->chcfg) & CHAN_CTX_POLLCFG_MASK) >> CHAN_CTX_POLLCFG_SHIFT); =20 - seq_printf(m, " type: 0x%x event ring: %u", chan_ctxt->chtype, - chan_ctxt->erindex); + seq_printf(m, " type: 0x%x event ring: %u", le32_to_cpu(chan_ctxt->chtyp= e), + le32_to_cpu(chan_ctxt->erindex)); =20 seq_printf(m, " base: 0x%llx len: 0x%llx rp: 0x%llx wp: 0x%llx", - chan_ctxt->rbase, chan_ctxt->rlen, chan_ctxt->rp, - chan_ctxt->wp); + le64_to_cpu(chan_ctxt->rbase), le64_to_cpu(chan_ctxt->rlen), + le64_to_cpu(chan_ctxt->rp), le64_to_cpu(chan_ctxt->wp)); =20 seq_printf(m, " local rp: 0x%pK local wp: 0x%pK db: 0x%pad\n", ring->rp, ring->wp, diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c index f1ec34417592..4183945fc2c4 100644 --- a/drivers/bus/mhi/core/init.c +++ b/drivers/bus/mhi/core/init.c @@ -290,17 +290,17 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntr= l) if (mhi_chan->offload_ch) continue; =20 - tmp =3D chan_ctxt->chcfg; + tmp =3D le32_to_cpu(chan_ctxt->chcfg); tmp &=3D ~CHAN_CTX_CHSTATE_MASK; tmp |=3D (MHI_CH_STATE_DISABLED << CHAN_CTX_CHSTATE_SHIFT); tmp &=3D ~CHAN_CTX_BRSTMODE_MASK; tmp |=3D (mhi_chan->db_cfg.brstmode << CHAN_CTX_BRSTMODE_SHIFT); tmp &=3D ~CHAN_CTX_POLLCFG_MASK; tmp |=3D (mhi_chan->db_cfg.pollcfg << CHAN_CTX_POLLCFG_SHIFT); - chan_ctxt->chcfg =3D tmp; + chan_ctxt->chcfg =3D cpu_to_le32(tmp); =20 - chan_ctxt->chtype =3D mhi_chan->type; - chan_ctxt->erindex =3D mhi_chan->er_index; + chan_ctxt->chtype =3D cpu_to_le32(mhi_chan->type); + chan_ctxt->erindex =3D cpu_to_le32(mhi_chan->er_index); =20 mhi_chan->ch_state =3D MHI_CH_STATE_DISABLED; mhi_chan->tre_ring.db_addr =3D (void __iomem *)&chan_ctxt->wp; @@ -325,14 +325,14 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntr= l) if (mhi_event->offload_ev) continue; =20 - tmp =3D er_ctxt->intmod; + tmp =3D le32_to_cpu(er_ctxt->intmod); tmp &=3D ~EV_CTX_INTMODC_MASK; tmp &=3D ~EV_CTX_INTMODT_MASK; tmp |=3D (mhi_event->intmod << EV_CTX_INTMODT_SHIFT); - er_ctxt->intmod =3D tmp; + er_ctxt->intmod =3D cpu_to_le32(tmp); =20 - er_ctxt->ertype =3D MHI_ER_TYPE_VALID; - er_ctxt->msivec =3D mhi_event->irq; + er_ctxt->ertype =3D cpu_to_le32(MHI_ER_TYPE_VALID); + er_ctxt->msivec =3D cpu_to_le32(mhi_event->irq); mhi_event->db_cfg.db_mode =3D true; =20 ring->el_size =3D sizeof(struct mhi_tre); @@ -346,9 +346,9 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl) * ring is empty */ ring->rp =3D ring->wp =3D ring->base; - er_ctxt->rbase =3D ring->iommu_base; + er_ctxt->rbase =3D cpu_to_le64(ring->iommu_base); er_ctxt->rp =3D er_ctxt->wp =3D er_ctxt->rbase; - er_ctxt->rlen =3D ring->len; + er_ctxt->rlen =3D cpu_to_le64(ring->len); ring->ctxt_wp =3D &er_ctxt->wp; } =20 @@ -375,9 +375,9 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl) goto error_alloc_cmd; =20 ring->rp =3D ring->wp =3D ring->base; - cmd_ctxt->rbase =3D ring->iommu_base; + cmd_ctxt->rbase =3D cpu_to_le64(ring->iommu_base); cmd_ctxt->rp =3D cmd_ctxt->wp =3D cmd_ctxt->rbase; - cmd_ctxt->rlen =3D ring->len; + cmd_ctxt->rlen =3D cpu_to_le64(ring->len); ring->ctxt_wp =3D &cmd_ctxt->wp; } =20 @@ -578,10 +578,10 @@ void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_= cntrl, chan_ctxt->rp =3D 0; chan_ctxt->wp =3D 0; =20 - tmp =3D chan_ctxt->chcfg; + tmp =3D le32_to_cpu(chan_ctxt->chcfg); tmp &=3D ~CHAN_CTX_CHSTATE_MASK; tmp |=3D (MHI_CH_STATE_DISABLED << CHAN_CTX_CHSTATE_SHIFT); - chan_ctxt->chcfg =3D tmp; + chan_ctxt->chcfg =3D cpu_to_le32(tmp); =20 /* Update to all cores */ smp_wmb(); @@ -615,14 +615,14 @@ int mhi_init_chan_ctxt(struct mhi_controller *mhi_cnt= rl, return -ENOMEM; } =20 - tmp =3D chan_ctxt->chcfg; + tmp =3D le32_to_cpu(chan_ctxt->chcfg); tmp &=3D ~CHAN_CTX_CHSTATE_MASK; tmp |=3D (MHI_CH_STATE_ENABLED << CHAN_CTX_CHSTATE_SHIFT); - chan_ctxt->chcfg =3D tmp; + chan_ctxt->chcfg =3D cpu_to_le32(tmp); =20 - chan_ctxt->rbase =3D tre_ring->iommu_base; + chan_ctxt->rbase =3D cpu_to_le64(tre_ring->iommu_base); chan_ctxt->rp =3D chan_ctxt->wp =3D chan_ctxt->rbase; - chan_ctxt->rlen =3D tre_ring->len; + chan_ctxt->rlen =3D cpu_to_le64(tre_ring->len); tre_ring->ctxt_wp =3D &chan_ctxt->wp; =20 tre_ring->rp =3D tre_ring->wp =3D tre_ring->base; diff --git a/drivers/bus/mhi/core/internal.h b/drivers/bus/mhi/core/interna= l.h index 3a732afaf73e..c02c4d48b744 100644 --- a/drivers/bus/mhi/core/internal.h +++ b/drivers/bus/mhi/core/internal.h @@ -209,14 +209,14 @@ extern struct bus_type mhi_bus_type; #define EV_CTX_INTMODT_MASK GENMASK(31, 16) #define EV_CTX_INTMODT_SHIFT 16 struct mhi_event_ctxt { - __u32 intmod; - __u32 ertype; - __u32 msivec; - - __u64 rbase __packed __aligned(4); - __u64 rlen __packed __aligned(4); - __u64 rp __packed __aligned(4); - __u64 wp __packed __aligned(4); + __le32 intmod; + __le32 ertype; + __le32 msivec; + + __le64 rbase __packed __aligned(4); + __le64 rlen __packed __aligned(4); + __le64 rp __packed __aligned(4); + __le64 wp __packed __aligned(4); }; =20 #define CHAN_CTX_CHSTATE_MASK GENMASK(7, 0) @@ -227,25 +227,25 @@ struct mhi_event_ctxt { #define CHAN_CTX_POLLCFG_SHIFT 10 #define CHAN_CTX_RESERVED_MASK GENMASK(31, 16) struct mhi_chan_ctxt { - __u32 chcfg; - __u32 chtype; - __u32 erindex; - - __u64 rbase __packed __aligned(4); - __u64 rlen __packed __aligned(4); - __u64 rp __packed __aligned(4); - __u64 wp __packed __aligned(4); + __le32 chcfg; + __le32 chtype; + __le32 erindex; + + __le64 rbase __packed __aligned(4); + __le64 rlen __packed __aligned(4); + __le64 rp __packed __aligned(4); + __le64 wp __packed __aligned(4); }; =20 struct mhi_cmd_ctxt { - __u32 reserved0; - __u32 reserved1; - __u32 reserved2; - - __u64 rbase __packed __aligned(4); - __u64 rlen __packed __aligned(4); - __u64 rp __packed __aligned(4); - __u64 wp __packed __aligned(4); + __le32 reserved0; + __le32 reserved1; + __le32 reserved2; + + __le64 rbase __packed __aligned(4); + __le64 rlen __packed __aligned(4); + __le64 rp __packed __aligned(4); + __le64 wp __packed __aligned(4); }; =20 struct mhi_ctxt { @@ -258,8 +258,8 @@ struct mhi_ctxt { }; =20 struct mhi_tre { - u64 ptr; - u32 dword[2]; + __le64 ptr; + __le32 dword[2]; }; =20 struct bhi_vec_entry { @@ -277,57 +277,58 @@ enum mhi_cmd_type { /* No operation command */ #define MHI_TRE_CMD_NOOP_PTR (0) #define MHI_TRE_CMD_NOOP_DWORD0 (0) -#define MHI_TRE_CMD_NOOP_DWORD1 (MHI_CMD_NOP << 16) +#define MHI_TRE_CMD_NOOP_DWORD1 (cpu_to_le32(MHI_CMD_NOP << 16)) =20 /* Channel reset command */ #define MHI_TRE_CMD_RESET_PTR (0) #define MHI_TRE_CMD_RESET_DWORD0 (0) -#define MHI_TRE_CMD_RESET_DWORD1(chid) ((chid << 24) | \ - (MHI_CMD_RESET_CHAN << 16)) +#define MHI_TRE_CMD_RESET_DWORD1(chid) (cpu_to_le32((chid << 24) | \ + (MHI_CMD_RESET_CHAN << 16))) =20 /* Channel stop command */ #define MHI_TRE_CMD_STOP_PTR (0) #define MHI_TRE_CMD_STOP_DWORD0 (0) -#define MHI_TRE_CMD_STOP_DWORD1(chid) ((chid << 24) | \ - (MHI_CMD_STOP_CHAN << 16)) +#define MHI_TRE_CMD_STOP_DWORD1(chid) (cpu_to_le32((chid << 24) | \ + (MHI_CMD_STOP_CHAN << 16))) =20 /* Channel start command */ #define MHI_TRE_CMD_START_PTR (0) #define MHI_TRE_CMD_START_DWORD0 (0) -#define MHI_TRE_CMD_START_DWORD1(chid) ((chid << 24) | \ - (MHI_CMD_START_CHAN << 16)) +#define MHI_TRE_CMD_START_DWORD1(chid) (cpu_to_le32((chid << 24) | \ + (MHI_CMD_START_CHAN << 16))) =20 -#define MHI_TRE_GET_CMD_CHID(tre) (((tre)->dword[1] >> 24) & 0xFF) -#define MHI_TRE_GET_CMD_TYPE(tre) (((tre)->dword[1] >> 16) & 0xFF) +#define MHI_TRE_GET_DWORD(tre, word) (le32_to_cpu((tre)->dword[(word)])) +#define MHI_TRE_GET_CMD_CHID(tre) ((MHI_TRE_GET_DWORD(tre, 1) >> 24) & 0xF= F) +#define MHI_TRE_GET_CMD_TYPE(tre) ((MHI_TRE_GET_DWORD(tre, 1) >> 16) & 0xF= F) =20 /* Event descriptor macros */ -#define MHI_TRE_EV_PTR(ptr) (ptr) -#define MHI_TRE_EV_DWORD0(code, len) ((code << 24) | len) -#define MHI_TRE_EV_DWORD1(chid, type) ((chid << 24) | (type << 16)) -#define MHI_TRE_GET_EV_PTR(tre) ((tre)->ptr) -#define MHI_TRE_GET_EV_CODE(tre) (((tre)->dword[0] >> 24) & 0xFF) -#define MHI_TRE_GET_EV_LEN(tre) ((tre)->dword[0] & 0xFFFF) -#define MHI_TRE_GET_EV_CHID(tre) (((tre)->dword[1] >> 24) & 0xFF) -#define MHI_TRE_GET_EV_TYPE(tre) (((tre)->dword[1] >> 16) & 0xFF) -#define MHI_TRE_GET_EV_STATE(tre) (((tre)->dword[0] >> 24) & 0xFF) -#define MHI_TRE_GET_EV_EXECENV(tre) (((tre)->dword[0] >> 24) & 0xFF) -#define MHI_TRE_GET_EV_SEQ(tre) ((tre)->dword[0]) -#define MHI_TRE_GET_EV_TIME(tre) ((tre)->ptr) -#define MHI_TRE_GET_EV_COOKIE(tre) lower_32_bits((tre)->ptr) -#define MHI_TRE_GET_EV_VEID(tre) (((tre)->dword[0] >> 16) & 0xFF) -#define MHI_TRE_GET_EV_LINKSPEED(tre) (((tre)->dword[1] >> 24) & 0xFF) -#define MHI_TRE_GET_EV_LINKWIDTH(tre) ((tre)->dword[0] & 0xFF) +#define MHI_TRE_EV_PTR(ptr) (cpu_to_le64(ptr)) +#define MHI_TRE_EV_DWORD0(code, len) (cpu_to_le32((code << 24) | len)) +#define MHI_TRE_EV_DWORD1(chid, type) (cpu_to_le32((chid << 24) | (type <<= 16))) +#define MHI_TRE_GET_EV_PTR(tre) (le64_to_cpu((tre)->ptr)) +#define MHI_TRE_GET_EV_CODE(tre) ((MHI_TRE_GET_DWORD(tre, 0) >> 24) & 0xFF) +#define MHI_TRE_GET_EV_LEN(tre) (MHI_TRE_GET_DWORD(tre, 0) & 0xFFFF) +#define MHI_TRE_GET_EV_CHID(tre) ((MHI_TRE_GET_DWORD(tre, 1) >> 24) & 0xFF) +#define MHI_TRE_GET_EV_TYPE(tre) ((MHI_TRE_GET_DWORD(tre, 1) >> 16) & 0xFF) +#define MHI_TRE_GET_EV_STATE(tre) ((MHI_TRE_GET_DWORD(tre, 0) >> 24) & 0xF= F) +#define MHI_TRE_GET_EV_EXECENV(tre) ((MHI_TRE_GET_DWORD(tre, 0) >> 24) & 0= xFF) +#define MHI_TRE_GET_EV_SEQ(tre) MHI_TRE_GET_DWORD(tre, 0) +#define MHI_TRE_GET_EV_TIME(tre) (MHI_TRE_GET_EV_PTR(tre)) +#define MHI_TRE_GET_EV_COOKIE(tre) lower_32_bits(MHI_TRE_GET_EV_PTR(tre)) +#define MHI_TRE_GET_EV_VEID(tre) ((MHI_TRE_GET_DWORD(tre, 0) >> 16) & 0xFF) +#define MHI_TRE_GET_EV_LINKSPEED(tre) ((MHI_TRE_GET_DWORD(tre, 1) >> 24) &= 0xFF) +#define MHI_TRE_GET_EV_LINKWIDTH(tre) (MHI_TRE_GET_DWORD(tre, 0) & 0xFF) =20 /* Transfer descriptor macros */ -#define MHI_TRE_DATA_PTR(ptr) (ptr) -#define MHI_TRE_DATA_DWORD0(len) (len & MHI_MAX_MTU) -#define MHI_TRE_DATA_DWORD1(bei, ieot, ieob, chain) ((2 << 16) | (bei << 1= 0) \ - | (ieot << 9) | (ieob << 8) | chain) +#define MHI_TRE_DATA_PTR(ptr) (cpu_to_le64(ptr)) +#define MHI_TRE_DATA_DWORD0(len) (cpu_to_le32(len & MHI_MAX_MTU)) +#define MHI_TRE_DATA_DWORD1(bei, ieot, ieob, chain) (cpu_to_le32((2 << 16)= | (bei << 10) \ + | (ieot << 9) | (ieob << 8) | chain)) =20 /* RSC transfer descriptor macros */ -#define MHI_RSCTRE_DATA_PTR(ptr, len) (((u64)len << 48) | ptr) -#define MHI_RSCTRE_DATA_DWORD0(cookie) (cookie) -#define MHI_RSCTRE_DATA_DWORD1 (MHI_PKT_TYPE_COALESCING << 16) +#define MHI_RSCTRE_DATA_PTR(ptr, len) (cpu_to_le64(((u64)len << 48) | ptr)) +#define MHI_RSCTRE_DATA_DWORD0(cookie) (cpu_to_le32(cookie)) +#define MHI_RSCTRE_DATA_DWORD1 (cpu_to_le32(MHI_PKT_TYPE_COALESCING << 16)) =20 enum mhi_pkt_type { MHI_PKT_TYPE_INVALID =3D 0x0, @@ -499,7 +500,7 @@ struct state_transition { struct mhi_ring { dma_addr_t dma_handle; dma_addr_t iommu_base; - u64 *ctxt_wp; /* point to ctxt wp */ + __le64 *ctxt_wp; /* point to ctxt wp */ void *pre_aligned; void *base; void *rp; diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index b15c5bc37dd4..9a94b8d66f57 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -114,7 +114,7 @@ void mhi_ring_er_db(struct mhi_event *mhi_event) struct mhi_ring *ring =3D &mhi_event->ring; =20 mhi_event->db_cfg.process_db(mhi_event->mhi_cntrl, &mhi_event->db_cfg, - ring->db_addr, *ring->ctxt_wp); + ring->db_addr, le64_to_cpu(*ring->ctxt_wp)); } =20 void mhi_ring_cmd_db(struct mhi_controller *mhi_cntrl, struct mhi_cmd *mhi= _cmd) @@ -123,7 +123,7 @@ void mhi_ring_cmd_db(struct mhi_controller *mhi_cntrl, = struct mhi_cmd *mhi_cmd) struct mhi_ring *ring =3D &mhi_cmd->ring; =20 db =3D ring->iommu_base + (ring->wp - ring->base); - *ring->ctxt_wp =3D db; + *ring->ctxt_wp =3D cpu_to_le64(db); mhi_write_db(mhi_cntrl, ring->db_addr, db); } =20 @@ -140,7 +140,7 @@ void mhi_ring_chan_db(struct mhi_controller *mhi_cntrl, * before letting h/w know there is new element to fetch. */ dma_wmb(); - *ring->ctxt_wp =3D db; + *ring->ctxt_wp =3D cpu_to_le64(db); =20 mhi_chan->db_cfg.process_db(mhi_cntrl, &mhi_chan->db_cfg, ring->db_addr, db); @@ -432,7 +432,7 @@ irqreturn_t mhi_irq_handler(int irq_number, void *dev) struct mhi_event_ctxt *er_ctxt =3D &mhi_cntrl->mhi_ctxt->er_ctxt[mhi_event->er_index]; struct mhi_ring *ev_ring =3D &mhi_event->ring; - dma_addr_t ptr =3D er_ctxt->rp; + dma_addr_t ptr =3D le64_to_cpu(er_ctxt->rp); void *dev_rp; =20 if (!is_valid_ring_ptr(ev_ring, ptr)) { @@ -537,14 +537,14 @@ static void mhi_recycle_ev_ring_element(struct mhi_co= ntroller *mhi_cntrl, =20 /* Update the WP */ ring->wp +=3D ring->el_size; - ctxt_wp =3D *ring->ctxt_wp + ring->el_size; + ctxt_wp =3D le64_to_cpu(*ring->ctxt_wp) + ring->el_size; =20 if (ring->wp >=3D (ring->base + ring->len)) { ring->wp =3D ring->base; ctxt_wp =3D ring->iommu_base; } =20 - *ring->ctxt_wp =3D ctxt_wp; + *ring->ctxt_wp =3D cpu_to_le64(ctxt_wp); =20 /* Update the RP */ ring->rp +=3D ring->el_size; @@ -801,7 +801,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi= _cntrl, struct device *dev =3D &mhi_cntrl->mhi_dev->dev; u32 chan; int count =3D 0; - dma_addr_t ptr =3D er_ctxt->rp; + dma_addr_t ptr =3D le64_to_cpu(er_ctxt->rp); =20 /* * This is a quick check to avoid unnecessary event processing @@ -940,7 +940,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi= _cntrl, mhi_recycle_ev_ring_element(mhi_cntrl, ev_ring); local_rp =3D ev_ring->rp; =20 - ptr =3D er_ctxt->rp; + ptr =3D le64_to_cpu(er_ctxt->rp); if (!is_valid_ring_ptr(ev_ring, ptr)) { dev_err(&mhi_cntrl->mhi_dev->dev, "Event ring rp points outside of the event ring\n"); @@ -970,7 +970,7 @@ int mhi_process_data_event_ring(struct mhi_controller *= mhi_cntrl, int count =3D 0; u32 chan; struct mhi_chan *mhi_chan; - dma_addr_t ptr =3D er_ctxt->rp; + dma_addr_t ptr =3D le64_to_cpu(er_ctxt->rp); =20 if (unlikely(MHI_EVENT_ACCESS_INVALID(mhi_cntrl->pm_state))) return -EIO; @@ -1011,7 +1011,7 @@ int mhi_process_data_event_ring(struct mhi_controller= *mhi_cntrl, mhi_recycle_ev_ring_element(mhi_cntrl, ev_ring); local_rp =3D ev_ring->rp; =20 - ptr =3D er_ctxt->rp; + ptr =3D le64_to_cpu(er_ctxt->rp); if (!is_valid_ring_ptr(ev_ring, ptr)) { dev_err(&mhi_cntrl->mhi_dev->dev, "Event ring rp points outside of the event ring\n"); @@ -1529,7 +1529,7 @@ static void mhi_mark_stale_events(struct mhi_controll= er *mhi_cntrl, /* mark all stale events related to channel as STALE event */ spin_lock_irqsave(&mhi_event->lock, flags); =20 - ptr =3D er_ctxt->rp; + ptr =3D le64_to_cpu(er_ctxt->rp); if (!is_valid_ring_ptr(ev_ring, ptr)) { dev_err(&mhi_cntrl->mhi_dev->dev, "Event ring rp points outside of the event ring\n"); diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c index bb9a2043f3a2..1020268a075a 100644 --- a/drivers/bus/mhi/core/pm.c +++ b/drivers/bus/mhi/core/pm.c @@ -218,7 +218,7 @@ int mhi_ready_state_transition(struct mhi_controller *m= hi_cntrl) continue; =20 ring->wp =3D ring->base + ring->len - ring->el_size; - *ring->ctxt_wp =3D ring->iommu_base + ring->len - ring->el_size; + *ring->ctxt_wp =3D cpu_to_le64(ring->iommu_base + ring->len - ring->el_s= ize); /* Update all cores */ smp_wmb(); =20 @@ -420,7 +420,7 @@ static int mhi_pm_mission_mode_transition(struct mhi_co= ntroller *mhi_cntrl) continue; =20 ring->wp =3D ring->base + ring->len - ring->el_size; - *ring->ctxt_wp =3D ring->iommu_base + ring->len - ring->el_size; + *ring->ctxt_wp =3D cpu_to_le64(ring->iommu_base + ring->len - ring->el_s= ize); /* Update to all cores */ smp_wmb(); =20 diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c index d340d6864e13..d243526b23d8 100644 --- a/drivers/bus/mhi/pci_generic.c +++ b/drivers/bus/mhi/pci_generic.c @@ -327,6 +327,7 @@ static const struct mhi_pci_dev_info mhi_quectel_em1xx_= info =3D { .config =3D &modem_quectel_em1xx_config, .bar_num =3D MHI_PCI_DEFAULT_BAR_NUM, .dma_data_width =3D 32, + .mru_default =3D 32768, .sideband_wake =3D true, }; =20 diff --git a/drivers/bus/mips_cdmm.c b/drivers/bus/mips_cdmm.c index 626dedd110cb..fca0d0669aa9 100644 --- a/drivers/bus/mips_cdmm.c +++ b/drivers/bus/mips_cdmm.c @@ -351,6 +351,7 @@ phys_addr_t __weak mips_cdmm_phys_base(void) np =3D of_find_compatible_node(NULL, NULL, "mti,mips-cdmm"); if (np) { err =3D of_address_to_resource(np, 0, &res); + of_node_put(np); if (!err) return res.start; } diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 814b3d0ca7b7..372859b43f89 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -414,7 +414,7 @@ config HW_RANDOM_MESON =20 config HW_RANDOM_CAVIUM tristate "Cavium ThunderX Random Number Generator support" - depends on HW_RANDOM && PCI && (ARM64 || (COMPILE_TEST && 64BIT)) + depends on HW_RANDOM && PCI && ARCH_THUNDER default HW_RANDOM help This driver provides kernel-side support for the Random Number diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/at= mel-rng.c index ecb71c4317a5..8cf0ef501341 100644 --- a/drivers/char/hw_random/atmel-rng.c +++ b/drivers/char/hw_random/atmel-rng.c @@ -114,6 +114,7 @@ static int atmel_trng_probe(struct platform_device *pde= v) =20 err_register: clk_disable_unprepare(trng->clk); + atmel_trng_disable(trng); return ret; } =20 diff --git a/drivers/char/hw_random/cavium-rng-vf.c b/drivers/char/hw_rando= m/cavium-rng-vf.c index 3de4a6a443ef..6f66919652bf 100644 --- a/drivers/char/hw_random/cavium-rng-vf.c +++ b/drivers/char/hw_random/cavium-rng-vf.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Hardware Random Number Generator support for Cavium, Inc. - * Thunder processor family. - * - * This file is subject to the terms and conditions of the GNU General Pub= lic - * License. See the file "COPYING" in the main directory of this archive - * for more details. + * Hardware Random Number Generator support. + * Cavium Thunder, Marvell OcteonTx/Tx2 processor families. * * Copyright (C) 2016 Cavium, Inc. */ @@ -15,16 +12,146 @@ #include #include =20 +#include + +/* PCI device IDs */ +#define PCI_DEVID_CAVIUM_RNG_PF 0xA018 +#define PCI_DEVID_CAVIUM_RNG_VF 0xA033 + +#define HEALTH_STATUS_REG 0x38 + +/* RST device info */ +#define PCI_DEVICE_ID_RST_OTX2 0xA085 +#define RST_BOOT_REG 0x1600ULL +#define CLOCK_BASE_RATE 50000000ULL +#define MSEC_TO_NSEC(x) (x * 1000000) + struct cavium_rng { struct hwrng ops; void __iomem *result; + void __iomem *pf_regbase; + struct pci_dev *pdev; + u64 clock_rate; + u64 prev_error; + u64 prev_time; }; =20 +static inline bool is_octeontx(struct pci_dev *pdev) +{ + if (midr_is_cpu_model_range(read_cpuid_id(), MIDR_THUNDERX_83XX, + MIDR_CPU_VAR_REV(0, 0), + MIDR_CPU_VAR_REV(3, 0)) || + midr_is_cpu_model_range(read_cpuid_id(), MIDR_THUNDERX_81XX, + MIDR_CPU_VAR_REV(0, 0), + MIDR_CPU_VAR_REV(3, 0)) || + midr_is_cpu_model_range(read_cpuid_id(), MIDR_THUNDERX, + MIDR_CPU_VAR_REV(0, 0), + MIDR_CPU_VAR_REV(3, 0))) + return true; + + return false; +} + +static u64 rng_get_coprocessor_clkrate(void) +{ + u64 ret =3D CLOCK_BASE_RATE * 16; /* Assume 800Mhz as default */ + struct pci_dev *pdev; + void __iomem *base; + + pdev =3D pci_get_device(PCI_VENDOR_ID_CAVIUM, + PCI_DEVICE_ID_RST_OTX2, NULL); + if (!pdev) + goto error; + + base =3D pci_ioremap_bar(pdev, 0); + if (!base) + goto error_put_pdev; + + /* RST: PNR_MUL * 50Mhz gives clockrate */ + ret =3D CLOCK_BASE_RATE * ((readq(base + RST_BOOT_REG) >> 33) & 0x3F); + + iounmap(base); + +error_put_pdev: + pci_dev_put(pdev); + +error: + return ret; +} + +static int check_rng_health(struct cavium_rng *rng) +{ + u64 cur_err, cur_time; + u64 status, cycles; + u64 time_elapsed; + + + /* Skip checking health for OcteonTx */ + if (!rng->pf_regbase) + return 0; + + status =3D readq(rng->pf_regbase + HEALTH_STATUS_REG); + if (status & BIT_ULL(0)) { + dev_err(&rng->pdev->dev, "HWRNG: Startup health test failed\n"); + return -EIO; + } + + cycles =3D status >> 1; + if (!cycles) + return 0; + + cur_time =3D arch_timer_read_counter(); + + /* RNM_HEALTH_STATUS[CYCLES_SINCE_HEALTH_FAILURE] + * Number of coprocessor cycles times 2 since the last failure. + * This field doesn't get cleared/updated until another failure. + */ + cycles =3D cycles / 2; + cur_err =3D (cycles * 1000000000) / rng->clock_rate; /* In nanosec */ + + /* Ignore errors that happenned a long time ago, these + * are most likely false positive errors. + */ + if (cur_err > MSEC_TO_NSEC(10)) { + rng->prev_error =3D 0; + rng->prev_time =3D 0; + return 0; + } + + if (rng->prev_error) { + /* Calculate time elapsed since last error + * '1' tick of CNTVCT is 10ns, since it runs at 100Mhz. + */ + time_elapsed =3D (cur_time - rng->prev_time) * 10; + time_elapsed +=3D rng->prev_error; + + /* Check if current error is a new one or the old one itself. + * If error is a new one then consider there is a persistent + * issue with entropy, declare hardware failure. + */ + if (cur_err < time_elapsed) { + dev_err(&rng->pdev->dev, "HWRNG failure detected\n"); + rng->prev_error =3D cur_err; + rng->prev_time =3D cur_time; + return -EIO; + } + } + + rng->prev_error =3D cur_err; + rng->prev_time =3D cur_time; + return 0; +} + /* Read data from the RNG unit */ static int cavium_rng_read(struct hwrng *rng, void *dat, size_t max, bool = wait) { struct cavium_rng *p =3D container_of(rng, struct cavium_rng, ops); unsigned int size =3D max; + int err =3D 0; + + err =3D check_rng_health(p); + if (err) + return err; =20 while (size >=3D 8) { *((u64 *)dat) =3D readq(p->result); @@ -39,6 +166,39 @@ static int cavium_rng_read(struct hwrng *rng, void *dat= , size_t max, bool wait) return max; } =20 +static int cavium_map_pf_regs(struct cavium_rng *rng) +{ + struct pci_dev *pdev; + + /* Health status is not supported on 83xx, skip mapping PF CSRs */ + if (is_octeontx(rng->pdev)) { + rng->pf_regbase =3D NULL; + return 0; + } + + pdev =3D pci_get_device(PCI_VENDOR_ID_CAVIUM, + PCI_DEVID_CAVIUM_RNG_PF, NULL); + if (!pdev) { + dev_err(&pdev->dev, "Cannot find RNG PF device\n"); + return -EIO; + } + + rng->pf_regbase =3D ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (!rng->pf_regbase) { + dev_err(&pdev->dev, "Failed to map PF CSR region\n"); + pci_dev_put(pdev); + return -ENOMEM; + } + + pci_dev_put(pdev); + + /* Get co-processor clock rate */ + rng->clock_rate =3D rng_get_coprocessor_clkrate(); + + return 0; +} + /* Map Cavium RNG to an HWRNG object */ static int cavium_rng_probe_vf(struct pci_dev *pdev, const struct pci_device_id *id) @@ -50,6 +210,8 @@ static int cavium_rng_probe_vf(struct pci_dev *pdev, if (!rng) return -ENOMEM; =20 + rng->pdev =3D pdev; + /* Map the RNG result */ rng->result =3D pcim_iomap(pdev, 0, 0); if (!rng->result) { @@ -67,6 +229,11 @@ static int cavium_rng_probe_vf(struct pci_dev *pdev, =20 pci_set_drvdata(pdev, rng); =20 + /* Health status is available only at PF, hence map PF registers. */ + ret =3D cavium_map_pf_regs(rng); + if (ret) + return ret; + ret =3D devm_hwrng_register(&pdev->dev, &rng->ops); if (ret) { dev_err(&pdev->dev, "Error registering device as HWRNG.\n"); @@ -76,10 +243,18 @@ static int cavium_rng_probe_vf(struct pci_dev *pdev, return 0; } =20 +/* Remove the VF */ +static void cavium_rng_remove_vf(struct pci_dev *pdev) +{ + struct cavium_rng *rng; + + rng =3D pci_get_drvdata(pdev); + iounmap(rng->pf_regbase); +} =20 static const struct pci_device_id cavium_rng_vf_id_table[] =3D { - { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa033), 0, 0, 0}, - {0,}, + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CAVIUM_RNG_VF) }, + { 0, } }; MODULE_DEVICE_TABLE(pci, cavium_rng_vf_id_table); =20 @@ -87,8 +262,9 @@ static struct pci_driver cavium_rng_vf_driver =3D { .name =3D "cavium_rng_vf", .id_table =3D cavium_rng_vf_id_table, .probe =3D cavium_rng_probe_vf, + .remove =3D cavium_rng_remove_vf, }; module_pci_driver(cavium_rng_vf_driver); =20 MODULE_AUTHOR("Omer Khaliq "); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/char/hw_random/cavium-rng.c b/drivers/char/hw_random/c= avium-rng.c index 63d6e68c24d2..b96579222408 100644 --- a/drivers/char/hw_random/cavium-rng.c +++ b/drivers/char/hw_random/cavium-rng.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Hardware Random Number Generator support for Cavium Inc. - * Thunder processor family. - * - * This file is subject to the terms and conditions of the GNU General Pub= lic - * License. See the file "COPYING" in the main directory of this archive - * for more details. + * Hardware Random Number Generator support. + * Cavium Thunder, Marvell OcteonTx/Tx2 processor families. * * Copyright (C) 2016 Cavium, Inc. */ @@ -91,4 +88,4 @@ static struct pci_driver cavium_rng_pf_driver =3D { =20 module_pci_driver(cavium_rng_pf_driver); MODULE_AUTHOR("Omer Khaliq "); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/char/hw_random/nomadik-rng.c b/drivers/char/hw_random/= nomadik-rng.c index 67947a19aa22..e8f9621e7954 100644 --- a/drivers/char/hw_random/nomadik-rng.c +++ b/drivers/char/hw_random/nomadik-rng.c @@ -65,14 +65,14 @@ static int nmk_rng_probe(struct amba_device *dev, const= struct amba_id *id) out_release: amba_release_regions(dev); out_clk: - clk_disable(rng_clk); + clk_disable_unprepare(rng_clk); return ret; } =20 static void nmk_rng_remove(struct amba_device *dev) { amba_release_regions(dev); - clk_disable(rng_clk); + clk_disable_unprepare(rng_clk); } =20 static const struct amba_id nmk_rng_ids[] =3D { diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index df37e7b6a10a..65d800ecc996 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -274,14 +274,6 @@ static void tpm_dev_release(struct device *dev) kfree(chip); } =20 -static void tpm_devs_release(struct device *dev) -{ - struct tpm_chip *chip =3D container_of(dev, struct tpm_chip, devs); - - /* release the master device reference */ - put_device(&chip->dev); -} - /** * tpm_class_shutdown() - prepare the TPM device for loss of power. * @dev: device to which the chip is associated. @@ -344,7 +336,6 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev, chip->dev_num =3D rc; =20 device_initialize(&chip->dev); - device_initialize(&chip->devs); =20 chip->dev.class =3D tpm_class; chip->dev.class->shutdown_pre =3D tpm_class_shutdown; @@ -352,29 +343,12 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev, chip->dev.parent =3D pdev; chip->dev.groups =3D chip->groups; =20 - chip->devs.parent =3D pdev; - chip->devs.class =3D tpmrm_class; - chip->devs.release =3D tpm_devs_release; - /* get extra reference on main device to hold on - * behalf of devs. This holds the chip structure - * while cdevs is in use. The corresponding put - * is in the tpm_devs_release (TPM2 only) - */ - if (chip->flags & TPM_CHIP_FLAG_TPM2) - get_device(&chip->dev); - if (chip->dev_num =3D=3D 0) chip->dev.devt =3D MKDEV(MISC_MAJOR, TPM_MINOR); else chip->dev.devt =3D MKDEV(MAJOR(tpm_devt), chip->dev_num); =20 - chip->devs.devt =3D - MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES); - rc =3D dev_set_name(&chip->dev, "tpm%d", chip->dev_num); - if (rc) - goto out; - rc =3D dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num); if (rc) goto out; =20 @@ -382,9 +356,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev, chip->flags |=3D TPM_CHIP_FLAG_VIRTUAL; =20 cdev_init(&chip->cdev, &tpm_fops); - cdev_init(&chip->cdevs, &tpmrm_fops); chip->cdev.owner =3D THIS_MODULE; - chip->cdevs.owner =3D THIS_MODULE; =20 rc =3D tpm2_init_space(&chip->work_space, TPM2_SPACE_BUFFER_SIZE); if (rc) { @@ -396,7 +368,6 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev, return chip; =20 out: - put_device(&chip->devs); put_device(&chip->dev); return ERR_PTR(rc); } @@ -445,14 +416,9 @@ static int tpm_add_char_device(struct tpm_chip *chip) } =20 if (chip->flags & TPM_CHIP_FLAG_TPM2) { - rc =3D cdev_device_add(&chip->cdevs, &chip->devs); - if (rc) { - dev_err(&chip->devs, - "unable to cdev_device_add() %s, major %d, minor %d, err=3D%d\n", - dev_name(&chip->devs), MAJOR(chip->devs.devt), - MINOR(chip->devs.devt), rc); - return rc; - } + rc =3D tpm_devs_add(chip); + if (rc) + goto err_del_cdev; } =20 /* Make the chip available. */ @@ -460,6 +426,10 @@ static int tpm_add_char_device(struct tpm_chip *chip) idr_replace(&dev_nums_idr, chip, chip->dev_num); mutex_unlock(&idr_lock); =20 + return 0; + +err_del_cdev: + cdev_device_del(&chip->cdev, &chip->dev); return rc; } =20 @@ -649,7 +619,7 @@ void tpm_chip_unregister(struct tpm_chip *chip) hwrng_unregister(&chip->hwrng); tpm_bios_log_teardown(chip); if (chip->flags & TPM_CHIP_FLAG_TPM2) - cdev_device_del(&chip->cdevs, &chip->devs); + tpm_devs_remove(chip); tpm_del_char_device(chip); } EXPORT_SYMBOL_GPL(tpm_chip_unregister); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 283f78211c3a..2163c6ee0d36 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -234,6 +234,8 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tp= m_space *space, u8 *cmd, size_t cmdsiz); int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, void= *buf, size_t *bufsiz); +int tpm_devs_add(struct tpm_chip *chip); +void tpm_devs_remove(struct tpm_chip *chip); =20 void tpm_bios_log_setup(struct tpm_chip *chip); void tpm_bios_log_teardown(struct tpm_chip *chip); diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c index d2225020e4d2..ffb35f0154c1 100644 --- a/drivers/char/tpm/tpm2-space.c +++ b/drivers/char/tpm/tpm2-space.c @@ -574,3 +574,68 @@ int tpm2_commit_space(struct tpm_chip *chip, struct tp= m_space *space, dev_err(&chip->dev, "%s: error %d\n", __func__, rc); return rc; } + +/* + * Put the reference to the main device. + */ +static void tpm_devs_release(struct device *dev) +{ + struct tpm_chip *chip =3D container_of(dev, struct tpm_chip, devs); + + /* release the master device reference */ + put_device(&chip->dev); +} + +/* + * Remove the device file for exposed TPM spaces and release the device + * reference. This may also release the reference to the master device. + */ +void tpm_devs_remove(struct tpm_chip *chip) +{ + cdev_device_del(&chip->cdevs, &chip->devs); + put_device(&chip->devs); +} + +/* + * Add a device file to expose TPM spaces. Also take a reference to the + * main device. + */ +int tpm_devs_add(struct tpm_chip *chip) +{ + int rc; + + device_initialize(&chip->devs); + chip->devs.parent =3D chip->dev.parent; + chip->devs.class =3D tpmrm_class; + + /* + * Get extra reference on main device to hold on behalf of devs. + * This holds the chip structure while cdevs is in use. The + * corresponding put is in the tpm_devs_release. + */ + get_device(&chip->dev); + chip->devs.release =3D tpm_devs_release; + chip->devs.devt =3D MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICE= S); + cdev_init(&chip->cdevs, &tpmrm_fops); + chip->cdevs.owner =3D THIS_MODULE; + + rc =3D dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num); + if (rc) + goto err_put_devs; + + rc =3D cdev_device_add(&chip->cdevs, &chip->devs); + if (rc) { + dev_err(&chip->devs, + "unable to cdev_device_add() %s, major %d, minor %d, err=3D%d\n", + dev_name(&chip->devs), MAJOR(chip->devs.devt), + MINOR(chip->devs.devt), rc); + goto err_put_devs; + } + + return 0; + +err_put_devs: + put_device(&chip->devs); + + return rc; +} diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 660c5c388c29..f864b17be7e3 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1957,6 +1957,13 @@ static void virtcons_remove(struct virtio_device *vd= ev) list_del(&portdev->list); spin_unlock_irq(&pdrvdata_lock); =20 + /* Device is going away, exit any polling for buffers */ + virtio_break_device(vdev); + if (use_multiport(portdev)) + flush_work(&portdev->control_work); + else + flush_work(&portdev->config_work); + /* Disable interrupts for vqs */ vdev->config->reset(vdev); /* Finish up work that's lined up */ diff --git a/drivers/clk/actions/owl-s700.c b/drivers/clk/actions/owl-s700.c index a2f34d13fb54..6ea7da1d6d75 100644 --- a/drivers/clk/actions/owl-s700.c +++ b/drivers/clk/actions/owl-s700.c @@ -162,6 +162,7 @@ static struct clk_div_table hdmia_div_table[] =3D { =20 static struct clk_div_table rmii_div_table[] =3D { {0, 4}, {1, 10}, + {0, 0} }; =20 /* divider clocks */ diff --git a/drivers/clk/actions/owl-s900.c b/drivers/clk/actions/owl-s900.c index 790890978424..5144ada2c7e1 100644 --- a/drivers/clk/actions/owl-s900.c +++ b/drivers/clk/actions/owl-s900.c @@ -140,7 +140,7 @@ static struct clk_div_table rmii_ref_div_table[] =3D { =20 static struct clk_div_table usb3_mac_div_table[] =3D { { 1, 2 }, { 2, 3 }, { 3, 4 }, - { 0, 8 }, + { 0, 0 } }; =20 static struct clk_div_table i2s_div_table[] =3D { diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index 369dfafabbca..060e908086a1 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -696,16 +696,16 @@ static const struct { { .n =3D "pdmc0_gclk", .id =3D 68, .r =3D { .max =3D 50000000 }, - .pp =3D { "syspll_divpmcck", "baudpll_divpmcck", }, - .pp_mux_table =3D { 5, 8, }, + .pp =3D { "syspll_divpmcck", "audiopll_divpmcck", }, + .pp_mux_table =3D { 5, 9, }, .pp_count =3D 2, .pp_chg_id =3D INT_MIN, }, =20 { .n =3D "pdmc1_gclk", .id =3D 69, .r =3D { .max =3D 50000000, }, - .pp =3D { "syspll_divpmcck", "baudpll_divpmcck", }, - .pp_mux_table =3D { 5, 8, }, + .pp =3D { "syspll_divpmcck", "audiopll_divpmcck", }, + .pp_mux_table =3D { 5, 9, }, .pp_count =3D 2, .pp_chg_id =3D INT_MIN, }, =20 diff --git a/drivers/clk/clk-clps711x.c b/drivers/clk/clk-clps711x.c index a2c6486ef170..f8417ee2961a 100644 --- a/drivers/clk/clk-clps711x.c +++ b/drivers/clk/clk-clps711x.c @@ -28,11 +28,13 @@ static const struct clk_div_table spi_div_table[] =3D { { .val =3D 1, .div =3D 8, }, { .val =3D 2, .div =3D 2, }, { .val =3D 3, .div =3D 1, }, + { /* sentinel */ } }; =20 static const struct clk_div_table timer_div_table[] =3D { { .val =3D 0, .div =3D 256, }, { .val =3D 1, .div =3D 1, }, + { /* sentinel */ } }; =20 struct clps711x_clk { diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 21b17d6ced6d..2c5db2df9d42 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3413,6 +3413,19 @@ static void clk_core_reparent_orphans_nolock(void) __clk_set_parent_after(orphan, parent, NULL); __clk_recalc_accuracies(orphan); __clk_recalc_rates(orphan, 0); + + /* + * __clk_init_parent() will set the initial req_rate to + * 0 if the clock doesn't have clk_ops::recalc_rate and + * is an orphan when it's registered. + * + * 'req_rate' is used by clk_set_rate_range() and + * clk_put() to trigger a clk_set_rate() call whenever + * the boundaries are modified. Let's make sure + * 'req_rate' is set to something non-zero so that + * clk_set_rate_range() doesn't drop the frequency. + */ + orphan->req_rate =3D orphan->rate; } } } @@ -3733,8 +3746,9 @@ struct clk *clk_hw_create_clk(struct device *dev, str= uct clk_hw *hw, struct clk *clk_hw_get_clk(struct clk_hw *hw, const char *con_id) { struct device *dev =3D hw->core->dev; + const char *name =3D dev ? dev_name(dev) : NULL; =20 - return clk_hw_create_clk(dev, hw, dev_name(dev), con_id); + return clk_hw_create_clk(dev, hw, name, con_id); } EXPORT_SYMBOL(clk_hw_get_clk); =20 diff --git a/drivers/clk/hisilicon/clk-hi3559a.c b/drivers/clk/hisilicon/cl= k-hi3559a.c index 56012a3d0219..9ea1a80acbe8 100644 --- a/drivers/clk/hisilicon/clk-hi3559a.c +++ b/drivers/clk/hisilicon/clk-hi3559a.c @@ -611,8 +611,8 @@ static struct hisi_mux_clock hi3559av100_shub_mux_clks[= ] =3D { =20 =20 /* shub div clk */ -static struct clk_div_table shub_spi_clk_table[] =3D {{0, 8}, {1, 4}, {2, = 2}}; -static struct clk_div_table shub_uart_div_clk_table[] =3D {{1, 8}, {2, 4}}; +static struct clk_div_table shub_spi_clk_table[] =3D {{0, 8}, {1, 4}, {2, = 2}, {/*sentinel*/}}; +static struct clk_div_table shub_uart_div_clk_table[] =3D {{1, 8}, {2, 4},= {/*sentinel*/}}; =20 static struct hisi_divider_clock hi3559av100_shub_div_clks[] =3D { { HI3559AV100_SHUB_SPI_SOURCE_CLK, "clk_spi_clk", "shub_clk", 0, 0x20, 24= , 2, diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index c4e0f1c07192..3f6fd7ef2a68 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -849,7 +849,6 @@ static void __init imx7d_clocks_init(struct device_node= *ccm_node) hws[IMX7D_WDOG4_ROOT_CLK] =3D imx_clk_hw_gate4("wdog4_root_clk", "wdog_po= st_div", base + 0x49f0, 0); hws[IMX7D_KPP_ROOT_CLK] =3D imx_clk_hw_gate4("kpp_root_clk", "ipg_root_cl= k", base + 0x4aa0, 0); hws[IMX7D_CSI_MCLK_ROOT_CLK] =3D imx_clk_hw_gate4("csi_mclk_root_clk", "c= si_mclk_post_div", base + 0x4490, 0); - hws[IMX7D_AUDIO_MCLK_ROOT_CLK] =3D imx_clk_hw_gate4("audio_mclk_root_clk"= , "audio_mclk_post_div", base + 0x4790, 0); hws[IMX7D_WRCLK_ROOT_CLK] =3D imx_clk_hw_gate4("wrclk_root_clk", "wrclk_p= ost_div", base + 0x47a0, 0); hws[IMX7D_USB_CTRL_CLK] =3D imx_clk_hw_gate4("usb_ctrl_clk", "ahb_root_cl= k", base + 0x4680, 0); hws[IMX7D_USB_PHY1_CLK] =3D imx_clk_hw_gate4("usb_phy1_clk", "pll_usb1_ma= in_clk", base + 0x46a0, 0); diff --git a/drivers/clk/imx/clk-imx8qxp-lpcg.c b/drivers/clk/imx/clk-imx8q= xp-lpcg.c index b23758083ce5..5e31a6a24b3a 100644 --- a/drivers/clk/imx/clk-imx8qxp-lpcg.c +++ b/drivers/clk/imx/clk-imx8qxp-lpcg.c @@ -248,7 +248,7 @@ static int imx_lpcg_parse_clks_from_dt(struct platform_= device *pdev, =20 for (i =3D 0; i < count; i++) { idx =3D bit_offset[i] / 4; - if (idx > IMX_LPCG_MAX_CLKS) { + if (idx >=3D IMX_LPCG_MAX_CLKS) { dev_warn(&pdev->dev, "invalid bit offset of clock %d\n", i); ret =3D -EINVAL; diff --git a/drivers/clk/loongson1/clk-loongson1c.c b/drivers/clk/loongson1= /clk-loongson1c.c index 703f87622cf5..1ebf740380ef 100644 --- a/drivers/clk/loongson1/clk-loongson1c.c +++ b/drivers/clk/loongson1/clk-loongson1c.c @@ -37,6 +37,7 @@ static const struct clk_div_table ahb_div_table[] =3D { [1] =3D { .val =3D 1, .div =3D 4 }, [2] =3D { .val =3D 2, .div =3D 3 }, [3] =3D { .val =3D 3, .div =3D 3 }, + [4] =3D { /* sentinel */ } }; =20 void __init ls1x_clk_init(void) diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index e1b1b426fae4..f675fd969c4d 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -264,7 +264,7 @@ static int clk_rcg2_determine_floor_rate(struct clk_hw = *hw, =20 static int __clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tb= l *f) { - u32 cfg, mask; + u32 cfg, mask, d_val, not2d_val, n_minus_m; struct clk_hw *hw =3D &rcg->clkr.hw; int ret, index =3D qcom_find_src_index(hw, rcg->parent_map, f->src); =20 @@ -283,8 +283,17 @@ static int __clk_rcg2_configure(struct clk_rcg2 *rcg, = const struct freq_tbl *f) if (ret) return ret; =20 + /* Calculate 2d value */ + d_val =3D f->n; + + n_minus_m =3D f->n - f->m; + n_minus_m *=3D 2; + + d_val =3D clamp_t(u32, d_val, f->m, n_minus_m); + not2d_val =3D ~d_val & mask; + ret =3D regmap_update_bits(rcg->clkr.regmap, - RCG_D_OFFSET(rcg), mask, ~f->n); + RCG_D_OFFSET(rcg), mask, not2d_val); if (ret) return ret; } @@ -720,6 +729,7 @@ static const struct frac_entry frac_table_pixel[] =3D { { 2, 9 }, { 4, 9 }, { 1, 1 }, + { 2, 3 }, { } }; =20 diff --git a/drivers/clk/qcom/gcc-ipq8074.c b/drivers/clk/qcom/gcc-ipq8074.c index 108fe27bee10..541016db3c4b 100644 --- a/drivers/clk/qcom/gcc-ipq8074.c +++ b/drivers/clk/qcom/gcc-ipq8074.c @@ -60,11 +60,6 @@ static const struct parent_map gcc_xo_gpll0_gpll0_out_ma= in_div2_map[] =3D { { P_GPLL0_DIV2, 4 }, }; =20 -static const char * const gcc_xo_gpll0[] =3D { - "xo", - "gpll0", -}; - static const struct parent_map gcc_xo_gpll0_map[] =3D { { P_XO, 0 }, { P_GPLL0, 1 }, @@ -956,6 +951,11 @@ static struct clk_rcg2 blsp1_uart6_apps_clk_src =3D { }, }; =20 +static const struct clk_parent_data gcc_xo_gpll0[] =3D { + { .fw_name =3D "xo" }, + { .hw =3D &gpll0.clkr.hw }, +}; + static const struct freq_tbl ftbl_pcie_axi_clk_src[] =3D { F(19200000, P_XO, 1, 0, 0), F(200000000, P_GPLL0, 4, 0, 0), @@ -969,7 +969,7 @@ static struct clk_rcg2 pcie0_axi_clk_src =3D { .parent_map =3D gcc_xo_gpll0_map, .clkr.hw.init =3D &(struct clk_init_data){ .name =3D "pcie0_axi_clk_src", - .parent_names =3D gcc_xo_gpll0, + .parent_data =3D gcc_xo_gpll0, .num_parents =3D 2, .ops =3D &clk_rcg2_ops, }, @@ -1016,7 +1016,7 @@ static struct clk_rcg2 pcie1_axi_clk_src =3D { .parent_map =3D gcc_xo_gpll0_map, .clkr.hw.init =3D &(struct clk_init_data){ .name =3D "pcie1_axi_clk_src", - .parent_names =3D gcc_xo_gpll0, + .parent_data =3D gcc_xo_gpll0, .num_parents =3D 2, .ops =3D &clk_rcg2_ops, }, @@ -1074,7 +1074,7 @@ static struct clk_rcg2 sdcc1_apps_clk_src =3D { .name =3D "sdcc1_apps_clk_src", .parent_names =3D gcc_xo_gpll0_gpll2_gpll0_out_main_div2, .num_parents =3D 4, - .ops =3D &clk_rcg2_ops, + .ops =3D &clk_rcg2_floor_ops, }, }; =20 @@ -1330,7 +1330,7 @@ static struct clk_rcg2 nss_ce_clk_src =3D { .parent_map =3D gcc_xo_gpll0_map, .clkr.hw.init =3D &(struct clk_init_data){ .name =3D "nss_ce_clk_src", - .parent_names =3D gcc_xo_gpll0, + .parent_data =3D gcc_xo_gpll0, .num_parents =3D 2, .ops =3D &clk_rcg2_ops, }, @@ -4329,8 +4329,7 @@ static struct clk_rcg2 pcie0_rchng_clk_src =3D { .parent_map =3D gcc_xo_gpll0_map, .clkr.hw.init =3D &(struct clk_init_data){ .name =3D "pcie0_rchng_clk_src", - .parent_hws =3D (const struct clk_hw *[]) { - &gpll0.clkr.hw }, + .parent_data =3D gcc_xo_gpll0, .num_parents =3D 2, .ops =3D &clk_rcg2_ops, }, diff --git a/drivers/clk/qcom/gcc-msm8994.c b/drivers/clk/qcom/gcc-msm8994.c index 5df9f1ead48e..4a9eb845b050 100644 --- a/drivers/clk/qcom/gcc-msm8994.c +++ b/drivers/clk/qcom/gcc-msm8994.c @@ -76,6 +76,7 @@ static struct clk_alpha_pll gpll4_early =3D { =20 static struct clk_alpha_pll_postdiv gpll4 =3D { .offset =3D 0x1dc0, + .width =3D 4, .regs =3D clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .clkr.hw.init =3D &(struct clk_init_data){ .name =3D "gpll4", diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a0= 7g044-cpg.c index 47c16265fca9..3e72dd060ffa 100644 --- a/drivers/clk/renesas/r9a07g044-cpg.c +++ b/drivers/clk/renesas/r9a07g044-cpg.c @@ -78,8 +78,8 @@ static const struct cpg_core_clk r9a07g044_core_clks[] __= initconst =3D { DEF_FIXED(".osc", R9A07G044_OSCCLK, CLK_EXTAL, 1, 1), DEF_FIXED(".osc_div1000", CLK_OSC_DIV1000, CLK_EXTAL, 1, 1000), DEF_SAMPLL(".pll1", CLK_PLL1, CLK_EXTAL, PLL146_CONF(0)), - DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 133, 2), - DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 133, 2), + DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 200, 3), + DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 200, 3), DEF_FIXED(".pll3_400", CLK_PLL3_400, CLK_PLL3, 1, 4), DEF_FIXED(".pll3_533", CLK_PLL3_533, CLK_PLL3, 1, 3), =20 diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index b7be7e11b0df..bb8a844309bf 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -180,6 +180,7 @@ static void rockchip_fractional_approximation(struct cl= k_hw *hw, unsigned long rate, unsigned long *parent_rate, unsigned long *m, unsigned long *n) { + struct clk_fractional_divider *fd =3D to_clk_fd(hw); unsigned long p_rate, p_parent_rate; struct clk_hw *p_parent; =20 @@ -190,6 +191,8 @@ static void rockchip_fractional_approximation(struct cl= k_hw *hw, *parent_rate =3D p_parent_rate; } =20 + fd->flags |=3D CLK_FRAC_DIVIDER_POWER_OF_TWO_PS; + clk_fractional_divider_general_approximation(hw, rate, parent_rate, m, n); } =20 diff --git a/drivers/clk/tegra/clk-tegra124-emc.c b/drivers/clk/tegra/clk-t= egra124-emc.c index 74c1d894cca8..219c80653dbd 100644 --- a/drivers/clk/tegra/clk-tegra124-emc.c +++ b/drivers/clk/tegra/clk-tegra124-emc.c @@ -198,6 +198,7 @@ static struct tegra_emc *emc_ensure_emc_driver(struct t= egra_clk_emc *tegra) =20 tegra->emc =3D platform_get_drvdata(pdev); if (!tegra->emc) { + put_device(&pdev->dev); pr_err("%s: cannot find EMC driver\n", __func__); return NULL; } diff --git a/drivers/clk/uniphier/clk-uniphier-fixed-rate.c b/drivers/clk/u= niphier/clk-uniphier-fixed-rate.c index 5319cd380480..3bc55ab75314 100644 --- a/drivers/clk/uniphier/clk-uniphier-fixed-rate.c +++ b/drivers/clk/uniphier/clk-uniphier-fixed-rate.c @@ -24,6 +24,7 @@ struct clk_hw *uniphier_clk_register_fixed_rate(struct de= vice *dev, =20 init.name =3D name; init.ops =3D &clk_fixed_rate_ops; + init.flags =3D 0; init.parent_names =3D NULL; init.num_parents =3D 0; =20 diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index eb596ff9e7bb..279ddff81ab4 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -229,8 +229,10 @@ static int __init parse_pmtmr(char *arg) int ret; =20 ret =3D kstrtouint(arg, 16, &base); - if (ret) - return ret; + if (ret) { + pr_warn("PMTMR: invalid 'pmtmr=3D' value: '%s'\n", arg); + return 1; + } =20 pr_info("PMTMR IOPort override: 0x%04x -> 0x%04x\n", pmtmr_ioport, base); diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_= mct.c index 5e3e96d3d1b9..cc2a961ddd3b 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -504,11 +504,14 @@ static int exynos4_mct_dying_cpu(unsigned int cpu) return 0; } =20 -static int __init exynos4_timer_resources(struct device_node *np, void __i= omem *base) +static int __init exynos4_timer_resources(struct device_node *np) { - int err, cpu; struct clk *mct_clk, *tick_clk; =20 + reg_base =3D of_iomap(np, 0); + if (!reg_base) + panic("%s: unable to ioremap mct address space\n", __func__); + tick_clk =3D of_clk_get_by_name(np, "fin_pll"); if (IS_ERR(tick_clk)) panic("%s: unable to determine tick clock rate\n", __func__); @@ -519,9 +522,32 @@ static int __init exynos4_timer_resources(struct devic= e_node *np, void __iomem * panic("%s: unable to retrieve mct clock instance\n", __func__); clk_prepare_enable(mct_clk); =20 - reg_base =3D base; - if (!reg_base) - panic("%s: unable to ioremap mct address space\n", __func__); + return 0; +} + +static int __init exynos4_timer_interrupts(struct device_node *np, + unsigned int int_type) +{ + int nr_irqs, i, err, cpu; + + mct_int_type =3D int_type; + + /* This driver uses only one global timer interrupt */ + mct_irqs[MCT_G0_IRQ] =3D irq_of_parse_and_map(np, MCT_G0_IRQ); + + /* + * Find out the number of local irqs specified. The local + * timer irqs are specified after the four global timer + * irqs are specified. + */ + nr_irqs =3D of_irq_count(np); + if (nr_irqs > ARRAY_SIZE(mct_irqs)) { + pr_err("exynos-mct: too many (%d) interrupts configured in DT\n", + nr_irqs); + nr_irqs =3D ARRAY_SIZE(mct_irqs); + } + for (i =3D MCT_L0_IRQ; i < nr_irqs; i++) + mct_irqs[i] =3D irq_of_parse_and_map(np, i); =20 if (mct_int_type =3D=3D MCT_INT_PPI) { =20 @@ -532,11 +558,14 @@ static int __init exynos4_timer_resources(struct devi= ce_node *np, void __iomem * mct_irqs[MCT_L0_IRQ], err); } else { for_each_possible_cpu(cpu) { - int mct_irq =3D mct_irqs[MCT_L0_IRQ + cpu]; + int mct_irq; struct mct_clock_event_device *pcpu_mevt =3D per_cpu_ptr(&percpu_mct_tick, cpu); =20 pcpu_mevt->evt.irq =3D -1; + if (MCT_L0_IRQ + cpu >=3D ARRAY_SIZE(mct_irqs)) + break; + mct_irq =3D mct_irqs[MCT_L0_IRQ + cpu]; =20 irq_set_status_flags(mct_irq, IRQ_NOAUTOEN); if (request_irq(mct_irq, @@ -581,24 +610,13 @@ static int __init exynos4_timer_resources(struct devi= ce_node *np, void __iomem * =20 static int __init mct_init_dt(struct device_node *np, unsigned int int_typ= e) { - u32 nr_irqs, i; int ret; =20 - mct_int_type =3D int_type; - - /* This driver uses only one global timer interrupt */ - mct_irqs[MCT_G0_IRQ] =3D irq_of_parse_and_map(np, MCT_G0_IRQ); - - /* - * Find out the number of local irqs specified. The local - * timer irqs are specified after the four global timer - * irqs are specified. - */ - nr_irqs =3D of_irq_count(np); - for (i =3D MCT_L0_IRQ; i < nr_irqs; i++) - mct_irqs[i] =3D irq_of_parse_and_map(np, i); + ret =3D exynos4_timer_resources(np); + if (ret) + return ret; =20 - ret =3D exynos4_timer_resources(np, of_iomap(np, 0)); + ret =3D exynos4_timer_interrupts(np, int_type); if (ret) return ret; =20 diff --git a/drivers/clocksource/timer-microchip-pit64b.c b/drivers/clockso= urce/timer-microchip-pit64b.c index cfa4ec7ef396..790d2c9b42a7 100644 --- a/drivers/clocksource/timer-microchip-pit64b.c +++ b/drivers/clocksource/timer-microchip-pit64b.c @@ -165,7 +165,7 @@ static u64 mchp_pit64b_clksrc_read(struct clocksource *= cs) return mchp_pit64b_cnt_read(mchp_pit64b_cs_base); } =20 -static u64 mchp_pit64b_sched_read_clk(void) +static u64 notrace mchp_pit64b_sched_read_clk(void) { return mchp_pit64b_cnt_read(mchp_pit64b_cs_base); } diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c index 529cc6a51cdb..c3f54d9912be 100644 --- a/drivers/clocksource/timer-of.c +++ b/drivers/clocksource/timer-of.c @@ -157,9 +157,9 @@ static __init int timer_of_base_init(struct device_node= *np, of_base->base =3D of_base->name ? of_io_request_and_map(np, of_base->index, of_base->name) : of_iomap(np, of_base->index); - if (IS_ERR(of_base->base)) { - pr_err("Failed to iomap (%s)\n", of_base->name); - return PTR_ERR(of_base->base); + if (IS_ERR_OR_NULL(of_base->base)) { + pr_err("Failed to iomap (%s:%s)\n", np->name, of_base->name); + return of_base->base ? PTR_ERR(of_base->base) : -ENOMEM; } =20 return 0; diff --git a/drivers/clocksource/timer-ti-dm-systimer.c b/drivers/clocksour= ce/timer-ti-dm-systimer.c index 1fccb457fcc5..2737407ff069 100644 --- a/drivers/clocksource/timer-ti-dm-systimer.c +++ b/drivers/clocksource/timer-ti-dm-systimer.c @@ -694,9 +694,9 @@ static int __init dmtimer_percpu_quirk_init(struct devi= ce_node *np, u32 pa) return 0; } =20 - if (pa =3D=3D 0x48034000) /* dra7 dmtimer3 */ + if (pa =3D=3D 0x4882c000) /* dra7 dmtimer15 */ return dmtimer_percpu_timer_init(np, 0); - else if (pa =3D=3D 0x48036000) /* dra7 dmtimer4 */ + else if (pa =3D=3D 0x4882e000) /* dra7 dmtimer16 */ return dmtimer_percpu_timer_init(np, 1); =20 return 0; diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cp= ufreq-nvmem.c index d1744b5d9619..6dfa86971a75 100644 --- a/drivers/cpufreq/qcom-cpufreq-nvmem.c +++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c @@ -130,7 +130,7 @@ static void get_krait_bin_format_b(struct device *cpu_d= ev, } =20 /* Check PVS_BLOW_STATUS */ - pte_efuse =3D *(((u32 *)buf) + 4); + pte_efuse =3D *(((u32 *)buf) + 1); pte_efuse &=3D BIT(21); if (pte_efuse) { dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs); diff --git a/drivers/cpuidle/cpuidle-qcom-spm.c b/drivers/cpuidle/cpuidle-q= com-spm.c index 01e77913a414..5f27dcc6c110 100644 --- a/drivers/cpuidle/cpuidle-qcom-spm.c +++ b/drivers/cpuidle/cpuidle-qcom-spm.c @@ -155,6 +155,22 @@ static struct platform_driver spm_cpuidle_driver =3D { }, }; =20 +static bool __init qcom_spm_find_any_cpu(void) +{ + struct device_node *cpu_node, *saw_node; + + for_each_of_cpu_node(cpu_node) { + saw_node =3D of_parse_phandle(cpu_node, "qcom,saw", 0); + if (of_device_is_available(saw_node)) { + of_node_put(saw_node); + of_node_put(cpu_node); + return true; + } + of_node_put(saw_node); + } + return false; +} + static int __init qcom_spm_cpuidle_init(void) { struct platform_device *pdev; @@ -164,6 +180,10 @@ static int __init qcom_spm_cpuidle_init(void) if (ret) return ret; =20 + /* Make sure there is actually any CPU managed by the SPM */ + if (!qcom_spm_find_any_cpu()) + return 0; + pdev =3D platform_device_register_simple("qcom-spm-cpuidle", -1, NULL, 0); if (IS_ERR(pdev)) { diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c b/drivers/= crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c index 54ae8d16e493..35e3cadccac2 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c @@ -11,6 +11,7 @@ * You could find a link for the datasheet in Documentation/arm/sunxi.rst */ =20 +#include #include #include #include @@ -283,7 +284,9 @@ static int sun8i_ce_cipher_run(struct crypto_engine *en= gine, void *areq) =20 flow =3D rctx->flow; err =3D sun8i_ce_run_task(ce, flow, crypto_tfm_alg_name(breq->base.tfm)); + local_bh_disable(); crypto_finalize_skcipher_request(engine, breq, err); + local_bh_enable(); return 0; } =20 diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c b/drivers/cr= ypto/allwinner/sun8i-ce/sun8i-ce-hash.c index 88194718a806..859b7522faaa 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c @@ -9,6 +9,7 @@ * * You could find the datasheet in Documentation/arm/sunxi.rst */ +#include #include #include #include @@ -414,6 +415,8 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, voi= d *breq) theend: kfree(buf); kfree(result); + local_bh_disable(); crypto_finalize_hash_request(engine, breq, err); + local_bh_enable(); return 0; } diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c b/drivers/= crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c index 9ef1c85c4aaa..554e400d41ca 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c @@ -11,6 +11,7 @@ * You could find a link for the datasheet in Documentation/arm/sunxi.rst */ =20 +#include #include #include #include @@ -274,7 +275,9 @@ static int sun8i_ss_handle_cipher_request(struct crypto= _engine *engine, void *ar struct skcipher_request *breq =3D container_of(areq, struct skcipher_requ= est, base); =20 err =3D sun8i_ss_cipher(breq); + local_bh_disable(); crypto_finalize_skcipher_request(engine, breq, err); + local_bh_enable(); =20 return 0; } diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c b/drivers/cr= ypto/allwinner/sun8i-ss/sun8i-ss-core.c index 80e89066dbd1..319fe3279a71 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c @@ -30,6 +30,8 @@ static const struct ss_variant ss_a80_variant =3D { .alg_cipher =3D { SS_ALG_AES, SS_ALG_DES, SS_ALG_3DES, }, + .alg_hash =3D { SS_ID_NOTSUPP, SS_ID_NOTSUPP, SS_ID_NOTSUPP, SS_ID_NOTSUP= P, + }, .op_mode =3D { SS_OP_ECB, SS_OP_CBC, }, .ss_clks =3D { diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c b/drivers/cr= ypto/allwinner/sun8i-ss/sun8i-ss-hash.c index 3c073eb3db03..1a71ed49d233 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c @@ -9,6 +9,7 @@ * * You could find the datasheet in Documentation/arm/sunxi.rst */ +#include #include #include #include @@ -442,6 +443,8 @@ int sun8i_ss_hash_run(struct crypto_engine *engine, voi= d *breq) theend: kfree(pad); kfree(result); + local_bh_disable(); crypto_finalize_hash_request(engine, breq, err); + local_bh_enable(); return 0; } diff --git a/drivers/crypto/amlogic/amlogic-gxl-cipher.c b/drivers/crypto/a= mlogic/amlogic-gxl-cipher.c index c6865cbd334b..e79514fce731 100644 --- a/drivers/crypto/amlogic/amlogic-gxl-cipher.c +++ b/drivers/crypto/amlogic/amlogic-gxl-cipher.c @@ -265,7 +265,9 @@ static int meson_handle_cipher_request(struct crypto_en= gine *engine, struct skcipher_request *breq =3D container_of(areq, struct skcipher_requ= est, base); =20 err =3D meson_cipher(breq); + local_bh_disable(); crypto_finalize_skcipher_request(engine, breq, err); + local_bh_enable(); =20 return 0; } diff --git a/drivers/crypto/ccp/ccp-dmaengine.c b/drivers/crypto/ccp/ccp-dm= aengine.c index d718db224be4..7d4b4ad1db1f 100644 --- a/drivers/crypto/ccp/ccp-dmaengine.c +++ b/drivers/crypto/ccp/ccp-dmaengine.c @@ -632,6 +632,20 @@ static int ccp_terminate_all(struct dma_chan *dma_chan) return 0; } =20 +static void ccp_dma_release(struct ccp_device *ccp) +{ + struct ccp_dma_chan *chan; + struct dma_chan *dma_chan; + unsigned int i; + + for (i =3D 0; i < ccp->cmd_q_count; i++) { + chan =3D ccp->ccp_dma_chan + i; + dma_chan =3D &chan->dma_chan; + tasklet_kill(&chan->cleanup_tasklet); + list_del_rcu(&dma_chan->device_node); + } +} + int ccp_dmaengine_register(struct ccp_device *ccp) { struct ccp_dma_chan *chan; @@ -736,6 +750,7 @@ int ccp_dmaengine_register(struct ccp_device *ccp) return 0; =20 err_reg: + ccp_dma_release(ccp); kmem_cache_destroy(ccp->dma_desc_cache); =20 err_cache: @@ -752,6 +767,7 @@ void ccp_dmaengine_unregister(struct ccp_device *ccp) return; =20 dma_async_device_unregister(dma_dev); + ccp_dma_release(ccp); =20 kmem_cache_destroy(ccp->dma_desc_cache); kmem_cache_destroy(ccp->dma_cmd_cache); diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 581a1b13d5c3..de015995189f 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -241,7 +241,7 @@ static int __sev_platform_init_locked(int *error) struct psp_device *psp =3D psp_master; struct sev_data_init data; struct sev_device *sev; - int psp_ret, rc =3D 0; + int psp_ret =3D -1, rc =3D 0; =20 if (!psp || !psp->sev_data) return -ENODEV; diff --git a/drivers/crypto/ccree/cc_buffer_mgr.c b/drivers/crypto/ccree/cc= _buffer_mgr.c index a5e041d9d2cf..11e0278c8631 100644 --- a/drivers/crypto/ccree/cc_buffer_mgr.c +++ b/drivers/crypto/ccree/cc_buffer_mgr.c @@ -258,6 +258,13 @@ static int cc_map_sg(struct device *dev, struct scatte= rlist *sg, { int ret =3D 0; =20 + if (!nbytes) { + *mapped_nents =3D 0; + *lbytes =3D 0; + *nents =3D 0; + return 0; + } + *nents =3D cc_get_sgl_nents(dev, sg, nbytes, lbytes); if (*nents > max_sg_nents) { *nents =3D 0; diff --git a/drivers/crypto/ccree/cc_cipher.c b/drivers/crypto/ccree/cc_cip= her.c index 78833491f534..309da6334a0a 100644 --- a/drivers/crypto/ccree/cc_cipher.c +++ b/drivers/crypto/ccree/cc_cipher.c @@ -257,8 +257,8 @@ static void cc_cipher_exit(struct crypto_tfm *tfm) &ctx_p->user.key_dma_addr); =20 /* Free key buffer in context */ - kfree_sensitive(ctx_p->user.key); dev_dbg(dev, "Free key buffer in context. key=3D@%p\n", ctx_p->user.key); + kfree_sensitive(ctx_p->user.key); } =20 struct tdes_keys { diff --git a/drivers/crypto/gemini/sl3516-ce-cipher.c b/drivers/crypto/gemi= ni/sl3516-ce-cipher.c index c1c2b1d86663..f2be0a7d7f7a 100644 --- a/drivers/crypto/gemini/sl3516-ce-cipher.c +++ b/drivers/crypto/gemini/sl3516-ce-cipher.c @@ -264,7 +264,9 @@ static int sl3516_ce_handle_cipher_request(struct crypt= o_engine *engine, void *a struct skcipher_request *breq =3D container_of(areq, struct skcipher_requ= est, base); =20 err =3D sl3516_ce_cipher(breq); + local_bh_disable(); crypto_finalize_skcipher_request(engine, breq, err); + local_bh_enable(); =20 return 0; } diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 1dc6a27ba0e0..82d2b117e162 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -4145,7 +4145,7 @@ static void qm_vf_get_qos(struct hisi_qm *qm, u32 fun= _num) static int qm_vf_read_qos(struct hisi_qm *qm) { int cnt =3D 0; - int ret; + int ret =3D -EINVAL; =20 /* reset mailbox qos val */ qm->mb_qos =3D 0; diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hi= silicon/sec2/sec_crypto.c index 6a45bd23b363..090920ed50c8 100644 --- a/drivers/crypto/hisilicon/sec2/sec_crypto.c +++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c @@ -2284,9 +2284,10 @@ static int sec_aead_soft_crypto(struct sec_ctx *ctx, struct aead_request *aead_req, bool encrypt) { - struct aead_request *subreq =3D aead_request_ctx(aead_req); struct sec_auth_ctx *a_ctx =3D &ctx->a_ctx; struct device *dev =3D ctx->dev; + struct aead_request *subreq; + int ret; =20 /* Kunpeng920 aead mode not support input 0 size */ if (!a_ctx->fallback_aead_tfm) { @@ -2294,6 +2295,10 @@ static int sec_aead_soft_crypto(struct sec_ctx *ctx, return -EINVAL; } =20 + subreq =3D aead_request_alloc(a_ctx->fallback_aead_tfm, GFP_KERNEL); + if (!subreq) + return -ENOMEM; + aead_request_set_tfm(subreq, a_ctx->fallback_aead_tfm); aead_request_set_callback(subreq, aead_req->base.flags, aead_req->base.complete, aead_req->base.data); @@ -2301,8 +2306,13 @@ static int sec_aead_soft_crypto(struct sec_ctx *ctx, aead_req->cryptlen, aead_req->iv); aead_request_set_ad(subreq, aead_req->assoclen); =20 - return encrypt ? crypto_aead_encrypt(subreq) : - crypto_aead_decrypt(subreq); + if (encrypt) + ret =3D crypto_aead_encrypt(subreq); + else + ret =3D crypto_aead_decrypt(subreq); + aead_request_free(subreq); + + return ret; } =20 static int sec_aead_crypto(struct aead_request *a_req, bool encrypt) diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisi= licon/sec2/sec_main.c index 90551bf38b52..03d239cfdf8c 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -443,9 +443,11 @@ static int sec_engine_init(struct hisi_qm *qm) =20 writel(SEC_SAA_ENABLE, qm->io_base + SEC_SAA_EN_REG); =20 - /* Enable sm4 extra mode, as ctr/ecb */ - writel_relaxed(SEC_BD_ERR_CHK_EN0, - qm->io_base + SEC_BD_ERR_CHK_EN_REG0); + /* HW V2 enable sm4 extra mode, as ctr/ecb */ + if (qm->ver < QM_HW_V3) + writel_relaxed(SEC_BD_ERR_CHK_EN0, + qm->io_base + SEC_BD_ERR_CHK_EN_REG0); + /* Enable sm4 xts mode multiple iv */ writel_relaxed(SEC_BD_ERR_CHK_EN1, qm->io_base + SEC_BD_ERR_CHK_EN_REG1); diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c b/drivers/c= rypto/marvell/octeontx2/otx2_cptvf_algs.c index 877a948469bd..570074e23b60 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c @@ -1634,16 +1634,13 @@ static inline int cpt_register_algs(void) { int i, err =3D 0; =20 - if (!IS_ENABLED(CONFIG_DM_CRYPT)) { - for (i =3D 0; i < ARRAY_SIZE(otx2_cpt_skciphers); i++) - otx2_cpt_skciphers[i].base.cra_flags &=3D - ~CRYPTO_ALG_DEAD; - - err =3D crypto_register_skciphers(otx2_cpt_skciphers, - ARRAY_SIZE(otx2_cpt_skciphers)); - if (err) - return err; - } + for (i =3D 0; i < ARRAY_SIZE(otx2_cpt_skciphers); i++) + otx2_cpt_skciphers[i].base.cra_flags &=3D ~CRYPTO_ALG_DEAD; + + err =3D crypto_register_skciphers(otx2_cpt_skciphers, + ARRAY_SIZE(otx2_cpt_skciphers)); + if (err) + return err; =20 for (i =3D 0; i < ARRAY_SIZE(otx2_cpt_aeads); i++) otx2_cpt_aeads[i].base.cra_flags &=3D ~CRYPTO_ALG_DEAD; diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index d19e5ffb5104..d6f9e2fe863d 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -331,7 +331,7 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_= request *arq) memset(key + AES_KEYSIZE_128, 0, AES_KEYSIZE_128); } =20 - for_each_sg(req->src, src, sg_nents(src), i) { + for_each_sg(req->src, src, sg_nents(req->src), i) { src_buf =3D sg_virt(src); len =3D sg_dma_len(src); tlen +=3D len; diff --git a/drivers/crypto/rockchip/rk3288_crypto_skcipher.c b/drivers/cry= pto/rockchip/rk3288_crypto_skcipher.c index 1cece1a7d3f0..5bbf0d2722e1 100644 --- a/drivers/crypto/rockchip/rk3288_crypto_skcipher.c +++ b/drivers/crypto/rockchip/rk3288_crypto_skcipher.c @@ -506,7 +506,6 @@ struct rk_crypto_tmp rk_ecb_des3_ede_alg =3D { .exit =3D rk_ablk_exit_tfm, .min_keysize =3D DES3_EDE_KEY_SIZE, .max_keysize =3D DES3_EDE_KEY_SIZE, - .ivsize =3D DES_BLOCK_SIZE, .setkey =3D rk_tdes_setkey, .encrypt =3D rk_des3_ede_ecb_encrypt, .decrypt =3D rk_des3_ede_ecb_decrypt, diff --git a/drivers/crypto/vmx/Kconfig b/drivers/crypto/vmx/Kconfig index c85fab7ef0bd..b2c28b87f14b 100644 --- a/drivers/crypto/vmx/Kconfig +++ b/drivers/crypto/vmx/Kconfig @@ -2,7 +2,11 @@ config CRYPTO_DEV_VMX_ENCRYPT tristate "Encryption acceleration support on P8 CPU" depends on CRYPTO_DEV_VMX + select CRYPTO_AES + select CRYPTO_CBC + select CRYPTO_CTR select CRYPTO_GHASH + select CRYPTO_XTS default m help Support for VMX cryptographic acceleration instructions on Power8 CPU. diff --git a/drivers/cxl/core/bus.c b/drivers/cxl/core/bus.c index 46ce58376580..55e120350a29 100644 --- a/drivers/cxl/core/bus.c +++ b/drivers/cxl/core/bus.c @@ -182,6 +182,7 @@ static void cxl_decoder_release(struct device *dev) =20 ida_free(&port->decoder_ida, cxld->id); kfree(cxld); + put_device(&port->dev); } =20 static const struct device_type cxl_decoder_switch_type =3D { @@ -500,7 +501,10 @@ struct cxl_decoder *cxl_decoder_alloc(struct cxl_port = *port, int nr_targets) if (rc < 0) goto err; =20 + /* need parent to stick around to release the id */ + get_device(&port->dev); cxld->id =3D rc; + cxld->nr_targets =3D nr_targets; dev =3D &cxld->dev; device_initialize(dev); diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c index 41de4a136ecd..2e7027a3fef3 100644 --- a/drivers/cxl/core/regs.c +++ b/drivers/cxl/core/regs.c @@ -35,7 +35,7 @@ void cxl_probe_component_regs(struct device *dev, void __= iomem *base, struct cxl_component_reg_map *map) { int cap, cap_count; - u64 cap_array; + u32 cap_array; =20 *map =3D (struct cxl_component_reg_map) { 0 }; =20 @@ -45,11 +45,11 @@ void cxl_probe_component_regs(struct device *dev, void = __iomem *base, */ base +=3D CXL_CM_OFFSET; =20 - cap_array =3D readq(base + CXL_CM_CAP_HDR_OFFSET); + cap_array =3D readl(base + CXL_CM_CAP_HDR_OFFSET); =20 if (FIELD_GET(CXL_CM_CAP_HDR_ID_MASK, cap_array) !=3D CM_CAP_HDR_CAP_ID) { dev_err(dev, - "Couldn't locate the CXL.cache and CXL.mem capability array header./n"); + "Couldn't locate the CXL.cache and CXL.mem capability array header.\n"); return; } =20 diff --git a/drivers/dax/super.c b/drivers/dax/super.c index e20d0cef10a1..0e55dde937d2 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -612,6 +612,7 @@ static int dax_fs_init(void) static void dax_fs_exit(void) { kern_unmount(dax_mnt); + rcu_barrier(); kmem_cache_destroy(dax_cache); } =20 diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c index c57a609db75b..e7330684d3b8 100644 --- a/drivers/dma-buf/udmabuf.c +++ b/drivers/dma-buf/udmabuf.c @@ -190,6 +190,10 @@ static long udmabuf_create(struct miscdevice *device, if (ubuf->pagecount > pglimit) goto err; } + + if (!ubuf->pagecount) + goto err; + ubuf->pages =3D kmalloc_array(ubuf->pagecount, sizeof(*ubuf->pages), GFP_KERNEL); if (!ubuf->pages) { diff --git a/drivers/dma/hisi_dma.c b/drivers/dma/hisi_dma.c index 97c87a7cba87..43817ced3a3e 100644 --- a/drivers/dma/hisi_dma.c +++ b/drivers/dma/hisi_dma.c @@ -30,7 +30,7 @@ #define HISI_DMA_MODE 0x217c #define HISI_DMA_OFFSET 0x100 =20 -#define HISI_DMA_MSI_NUM 30 +#define HISI_DMA_MSI_NUM 32 #define HISI_DMA_CHAN_NUM 30 #define HISI_DMA_Q_DEPTH_VAL 1024 =20 diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index cd855097bfdb..4bafc88f425f 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -688,11 +688,16 @@ static void idxd_groups_clear_state(struct idxd_devic= e *idxd) memset(&group->grpcfg, 0, sizeof(group->grpcfg)); group->num_engines =3D 0; group->num_wqs =3D 0; - group->use_token_limit =3D false; - group->tokens_allowed =3D 0; - group->tokens_reserved =3D 0; - group->tc_a =3D -1; - group->tc_b =3D -1; + group->use_rdbuf_limit =3D false; + group->rdbufs_allowed =3D 0; + group->rdbufs_reserved =3D 0; + if (idxd->hw.version < DEVICE_VERSION_2 && !tc_override) { + group->tc_a =3D 1; + group->tc_b =3D 1; + } else { + group->tc_a =3D -1; + group->tc_b =3D -1; + } } } =20 @@ -788,10 +793,10 @@ static int idxd_groups_config_write(struct idxd_devic= e *idxd) int i; struct device *dev =3D &idxd->pdev->dev; =20 - /* Setup bandwidth token limit */ - if (idxd->hw.gen_cap.config_en && idxd->token_limit) { + /* Setup bandwidth rdbuf limit */ + if (idxd->hw.gen_cap.config_en && idxd->rdbuf_limit) { reg.bits =3D ioread32(idxd->reg_base + IDXD_GENCFG_OFFSET); - reg.token_limit =3D idxd->token_limit; + reg.rdbuf_limit =3D idxd->rdbuf_limit; iowrite32(reg.bits, idxd->reg_base + IDXD_GENCFG_OFFSET); } =20 @@ -932,13 +937,12 @@ static void idxd_group_flags_setup(struct idxd_device= *idxd) group->tc_b =3D group->grpcfg.flags.tc_b =3D 1; else group->grpcfg.flags.tc_b =3D group->tc_b; - group->grpcfg.flags.use_token_limit =3D group->use_token_limit; - group->grpcfg.flags.tokens_reserved =3D group->tokens_reserved; - if (group->tokens_allowed) - group->grpcfg.flags.tokens_allowed =3D - group->tokens_allowed; + group->grpcfg.flags.use_rdbuf_limit =3D group->use_rdbuf_limit; + group->grpcfg.flags.rdbufs_reserved =3D group->rdbufs_reserved; + if (group->rdbufs_allowed) + group->grpcfg.flags.rdbufs_allowed =3D group->rdbufs_allowed; else - group->grpcfg.flags.tokens_allowed =3D idxd->max_tokens; + group->grpcfg.flags.rdbufs_allowed =3D idxd->max_rdbufs; } } =20 @@ -1131,7 +1135,7 @@ int idxd_device_load_config(struct idxd_device *idxd) int i, rc; =20 reg.bits =3D ioread32(idxd->reg_base + IDXD_GENCFG_OFFSET); - idxd->token_limit =3D reg.token_limit; + idxd->rdbuf_limit =3D reg.rdbuf_limit; =20 for (i =3D 0; i < idxd->max_groups; i++) { struct idxd_group *group =3D idxd->groups[i]; diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index 0cf8d3145870..ca1e7bd05839 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -84,9 +84,9 @@ struct idxd_group { int id; int num_engines; int num_wqs; - bool use_token_limit; - u8 tokens_allowed; - u8 tokens_reserved; + bool use_rdbuf_limit; + u8 rdbufs_allowed; + u8 rdbufs_reserved; int tc_a; int tc_b; }; @@ -276,11 +276,11 @@ struct idxd_device { u32 max_batch_size; int max_groups; int max_engines; - int max_tokens; + int max_rdbufs; int max_wqs; int max_wq_size; - int token_limit; - int nr_tokens; /* non-reserved tokens */ + int rdbuf_limit; + int nr_rdbufs; /* non-reserved read buffers */ unsigned int wqcfg_size; =20 union sw_err_reg sw_err; diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index 7bf03f371ce1..6263d9825250 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -464,9 +464,9 @@ static void idxd_read_caps(struct idxd_device *idxd) dev_dbg(dev, "group_cap: %#llx\n", idxd->hw.group_cap.bits); idxd->max_groups =3D idxd->hw.group_cap.num_groups; dev_dbg(dev, "max groups: %u\n", idxd->max_groups); - idxd->max_tokens =3D idxd->hw.group_cap.total_tokens; - dev_dbg(dev, "max tokens: %u\n", idxd->max_tokens); - idxd->nr_tokens =3D idxd->max_tokens; + idxd->max_rdbufs =3D idxd->hw.group_cap.total_rdbufs; + dev_dbg(dev, "max read buffers: %u\n", idxd->max_rdbufs); + idxd->nr_rdbufs =3D idxd->max_rdbufs; =20 /* read engine capabilities */ idxd->hw.engine_cap.bits =3D diff --git a/drivers/dma/idxd/registers.h b/drivers/dma/idxd/registers.h index 262c8220adbd..ac4fe0b1dd8a 100644 --- a/drivers/dma/idxd/registers.h +++ b/drivers/dma/idxd/registers.h @@ -64,9 +64,9 @@ union wq_cap_reg { union group_cap_reg { struct { u64 num_groups:8; - u64 total_tokens:8; - u64 token_en:1; - u64 token_limit:1; + u64 total_rdbufs:8; /* formerly total_tokens */ + u64 rdbuf_ctrl:1; /* formerly token_en */ + u64 rdbuf_limit:1; /* formerly token_limit */ u64 rsvd:46; }; u64 bits; @@ -110,7 +110,7 @@ union offsets_reg { #define IDXD_GENCFG_OFFSET 0x80 union gencfg_reg { struct { - u32 token_limit:8; + u32 rdbuf_limit:8; u32 rsvd:4; u32 user_int_en:1; u32 rsvd2:19; @@ -287,10 +287,10 @@ union group_flags { u32 tc_a:3; u32 tc_b:3; u32 rsvd:1; - u32 use_token_limit:1; - u32 tokens_reserved:8; + u32 use_rdbuf_limit:1; + u32 rdbufs_reserved:8; u32 rsvd2:4; - u32 tokens_allowed:8; + u32 rdbufs_allowed:8; u32 rsvd3:4; }; u32 bits; diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index a9025be940db..999ce13a93ad 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -99,17 +99,17 @@ struct device_type idxd_engine_device_type =3D { =20 /* Group attributes */ =20 -static void idxd_set_free_tokens(struct idxd_device *idxd) +static void idxd_set_free_rdbufs(struct idxd_device *idxd) { - int i, tokens; + int i, rdbufs; =20 - for (i =3D 0, tokens =3D 0; i < idxd->max_groups; i++) { + for (i =3D 0, rdbufs =3D 0; i < idxd->max_groups; i++) { struct idxd_group *g =3D idxd->groups[i]; =20 - tokens +=3D g->tokens_reserved; + rdbufs +=3D g->rdbufs_reserved; } =20 - idxd->nr_tokens =3D idxd->max_tokens - tokens; + idxd->nr_rdbufs =3D idxd->max_rdbufs - rdbufs; } =20 static ssize_t group_tokens_reserved_show(struct device *dev, @@ -118,7 +118,7 @@ static ssize_t group_tokens_reserved_show(struct device= *dev, { struct idxd_group *group =3D confdev_to_group(dev); =20 - return sysfs_emit(buf, "%u\n", group->tokens_reserved); + return sysfs_emit(buf, "%u\n", group->rdbufs_reserved); } =20 static ssize_t group_tokens_reserved_store(struct device *dev, @@ -143,14 +143,14 @@ static ssize_t group_tokens_reserved_store(struct dev= ice *dev, if (idxd->state =3D=3D IDXD_DEV_ENABLED) return -EPERM; =20 - if (val > idxd->max_tokens) + if (val > idxd->max_rdbufs) return -EINVAL; =20 - if (val > idxd->nr_tokens + group->tokens_reserved) + if (val > idxd->nr_rdbufs + group->rdbufs_reserved) return -EINVAL; =20 - group->tokens_reserved =3D val; - idxd_set_free_tokens(idxd); + group->rdbufs_reserved =3D val; + idxd_set_free_rdbufs(idxd); return count; } =20 @@ -164,7 +164,7 @@ static ssize_t group_tokens_allowed_show(struct device = *dev, { struct idxd_group *group =3D confdev_to_group(dev); =20 - return sysfs_emit(buf, "%u\n", group->tokens_allowed); + return sysfs_emit(buf, "%u\n", group->rdbufs_allowed); } =20 static ssize_t group_tokens_allowed_store(struct device *dev, @@ -190,10 +190,10 @@ static ssize_t group_tokens_allowed_store(struct devi= ce *dev, return -EPERM; =20 if (val < 4 * group->num_engines || - val > group->tokens_reserved + idxd->nr_tokens) + val > group->rdbufs_reserved + idxd->nr_rdbufs) return -EINVAL; =20 - group->tokens_allowed =3D val; + group->rdbufs_allowed =3D val; return count; } =20 @@ -207,7 +207,7 @@ static ssize_t group_use_token_limit_show(struct device= *dev, { struct idxd_group *group =3D confdev_to_group(dev); =20 - return sysfs_emit(buf, "%u\n", group->use_token_limit); + return sysfs_emit(buf, "%u\n", group->use_rdbuf_limit); } =20 static ssize_t group_use_token_limit_store(struct device *dev, @@ -232,10 +232,10 @@ static ssize_t group_use_token_limit_store(struct dev= ice *dev, if (idxd->state =3D=3D IDXD_DEV_ENABLED) return -EPERM; =20 - if (idxd->token_limit =3D=3D 0) + if (idxd->rdbuf_limit =3D=3D 0) return -EPERM; =20 - group->use_token_limit =3D !!val; + group->use_rdbuf_limit =3D !!val; return count; } =20 @@ -1161,7 +1161,7 @@ static ssize_t max_tokens_show(struct device *dev, { struct idxd_device *idxd =3D confdev_to_idxd(dev); =20 - return sysfs_emit(buf, "%u\n", idxd->max_tokens); + return sysfs_emit(buf, "%u\n", idxd->max_rdbufs); } static DEVICE_ATTR_RO(max_tokens); =20 @@ -1170,7 +1170,7 @@ static ssize_t token_limit_show(struct device *dev, { struct idxd_device *idxd =3D confdev_to_idxd(dev); =20 - return sysfs_emit(buf, "%u\n", idxd->token_limit); + return sysfs_emit(buf, "%u\n", idxd->rdbuf_limit); } =20 static ssize_t token_limit_store(struct device *dev, @@ -1191,13 +1191,13 @@ static ssize_t token_limit_store(struct device *dev, if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) return -EPERM; =20 - if (!idxd->hw.group_cap.token_limit) + if (!idxd->hw.group_cap.rdbuf_limit) return -EPERM; =20 - if (val > idxd->hw.group_cap.total_tokens) + if (val > idxd->hw.group_cap.total_rdbufs) return -EINVAL; =20 - idxd->token_limit =3D val; + idxd->rdbuf_limit =3D val; return count; } static DEVICE_ATTR_RW(token_limit); diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-p= store.c index 0ef086e43090..7e771c56c13c 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c @@ -266,7 +266,7 @@ static int efi_pstore_write(struct pstore_record *recor= d) efi_name[i] =3D name[i]; =20 ret =3D efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES, - preemptible(), record->size, record->psi->buf); + false, record->size, record->psi->buf); =20 if (record->reason =3D=3D KMSG_DUMP_OOPS && try_module_get(THIS_MODULE)) if (!schedule_work(&efivar_work)) diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kcon= fig index 931544c9f63d..983e07dc022e 100644 --- a/drivers/firmware/google/Kconfig +++ b/drivers/firmware/google/Kconfig @@ -21,7 +21,7 @@ config GOOGLE_SMI =20 config GOOGLE_COREBOOT_TABLE tristate "Coreboot Table Access" - depends on ACPI || OF + depends on HAS_IOMEM && (ACPI || OF) help This option enables the coreboot_table module, which provides other firmware modules access to the coreboot table. The coreboot table diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 7db8066b19fd..3f67bf774821 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -749,12 +749,6 @@ int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size= , u32 spare) }; int ret; =20 - desc.args[0] =3D addr; - desc.args[1] =3D size; - desc.args[2] =3D spare; - desc.arginfo =3D QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL, - QCOM_SCM_VAL); - ret =3D qcom_scm_call(__scm->dev, &desc, NULL); =20 /* the pg table has been initialized already, ignore the error */ diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-= svc.c index 29c0a616b317..c4bf934e3553 100644 --- a/drivers/firmware/stratix10-svc.c +++ b/drivers/firmware/stratix10-svc.c @@ -477,7 +477,7 @@ static int svc_normal_to_secure_thread(void *data) case INTEL_SIP_SMC_RSU_ERROR: pr_err("%s: STATUS_ERROR\n", __func__); cbdata->status =3D BIT(SVC_STATUS_ERROR); - cbdata->kaddr1 =3D NULL; + cbdata->kaddr1 =3D &res.a1; cbdata->kaddr2 =3D NULL; cbdata->kaddr3 =3D NULL; pdata->chan->scl->receive_cb(pdata->chan->scl, cbdata); diff --git a/drivers/firmware/sysfb_simplefb.c b/drivers/firmware/sysfb_sim= plefb.c index 303a491e520d..757cc8b9f3de 100644 --- a/drivers/firmware/sysfb_simplefb.c +++ b/drivers/firmware/sysfb_simplefb.c @@ -113,16 +113,21 @@ __init int sysfb_create_simplefb(const struct screen_= info *si, sysfb_apply_efi_quirks(pd); =20 ret =3D platform_device_add_resources(pd, &res, 1); - if (ret) { - platform_device_put(pd); - return ret; - } + if (ret) + goto err_put_device; =20 ret =3D platform_device_add_data(pd, mode, sizeof(*mode)); - if (ret) { - platform_device_put(pd); - return ret; - } + if (ret) + goto err_put_device; + + ret =3D platform_device_add(pd); + if (ret) + goto err_put_device; + + return 0; + +err_put_device: + platform_device_put(pd); =20 - return platform_device_add(pd); + return ret; } diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspee= d.c index 8606e55c1721..0bed2fab8055 100644 --- a/drivers/fsi/fsi-master-aspeed.c +++ b/drivers/fsi/fsi-master-aspeed.c @@ -542,25 +542,28 @@ static int fsi_master_aspeed_probe(struct platform_de= vice *pdev) return rc; } =20 - aspeed =3D devm_kzalloc(&pdev->dev, sizeof(*aspeed), GFP_KERNEL); + aspeed =3D kzalloc(sizeof(*aspeed), GFP_KERNEL); if (!aspeed) return -ENOMEM; =20 aspeed->dev =3D &pdev->dev; =20 aspeed->base =3D devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(aspeed->base)) - return PTR_ERR(aspeed->base); + if (IS_ERR(aspeed->base)) { + rc =3D PTR_ERR(aspeed->base); + goto err_free_aspeed; + } =20 aspeed->clk =3D devm_clk_get(aspeed->dev, NULL); if (IS_ERR(aspeed->clk)) { dev_err(aspeed->dev, "couldn't get clock\n"); - return PTR_ERR(aspeed->clk); + rc =3D PTR_ERR(aspeed->clk); + goto err_free_aspeed; } rc =3D clk_prepare_enable(aspeed->clk); if (rc) { dev_err(aspeed->dev, "couldn't enable clock\n"); - return rc; + goto err_free_aspeed; } =20 rc =3D setup_cfam_reset(aspeed); @@ -595,7 +598,7 @@ static int fsi_master_aspeed_probe(struct platform_devi= ce *pdev) rc =3D opb_readl(aspeed, ctrl_base + FSI_MVER, &raw); if (rc) { dev_err(&pdev->dev, "failed to read hub version\n"); - return rc; + goto err_release; } =20 reg =3D be32_to_cpu(raw); @@ -634,6 +637,8 @@ static int fsi_master_aspeed_probe(struct platform_devi= ce *pdev) =20 err_release: clk_disable_unprepare(aspeed->clk); +err_free_aspeed: + kfree(aspeed); return rc; } =20 diff --git a/drivers/fsi/fsi-scom.c b/drivers/fsi/fsi-scom.c index da1486bb6a14..bcb756dc9866 100644 --- a/drivers/fsi/fsi-scom.c +++ b/drivers/fsi/fsi-scom.c @@ -145,7 +145,7 @@ static int put_indirect_scom_form0(struct scom_device *= scom, uint64_t value, uint64_t addr, uint32_t *status) { uint64_t ind_data, ind_addr; - int rc, retries, err =3D 0; + int rc, err; =20 if (value & ~XSCOM_DATA_IND_DATA) return -EINVAL; @@ -156,19 +156,14 @@ static int put_indirect_scom_form0(struct scom_device= *scom, uint64_t value, if (rc || (*status & SCOM_STATUS_ANY_ERR)) return rc; =20 - for (retries =3D 0; retries < SCOM_MAX_IND_RETRIES; retries++) { - rc =3D __get_scom(scom, &ind_data, addr, status); - if (rc || (*status & SCOM_STATUS_ANY_ERR)) - return rc; + rc =3D __get_scom(scom, &ind_data, addr, status); + if (rc || (*status & SCOM_STATUS_ANY_ERR)) + return rc; =20 - err =3D (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT; - *status =3D err << SCOM_STATUS_PIB_RESP_SHIFT; - if ((ind_data & XSCOM_DATA_IND_COMPLETE) || (err !=3D SCOM_PIB_BLOCKED)) - return 0; + err =3D (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT; + *status =3D err << SCOM_STATUS_PIB_RESP_SHIFT; =20 - msleep(1); - } - return rc; + return 0; } =20 static int put_indirect_scom_form1(struct scom_device *scom, uint64_t valu= e, @@ -188,7 +183,7 @@ static int get_indirect_scom_form0(struct scom_device *= scom, uint64_t *value, uint64_t addr, uint32_t *status) { uint64_t ind_data, ind_addr; - int rc, retries, err =3D 0; + int rc, err; =20 ind_addr =3D addr & XSCOM_ADDR_DIRECT_PART; ind_data =3D (addr & XSCOM_ADDR_INDIRECT_PART) | XSCOM_DATA_IND_READ; @@ -196,21 +191,15 @@ static int get_indirect_scom_form0(struct scom_device= *scom, uint64_t *value, if (rc || (*status & SCOM_STATUS_ANY_ERR)) return rc; =20 - for (retries =3D 0; retries < SCOM_MAX_IND_RETRIES; retries++) { - rc =3D __get_scom(scom, &ind_data, addr, status); - if (rc || (*status & SCOM_STATUS_ANY_ERR)) - return rc; - - err =3D (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT; - *status =3D err << SCOM_STATUS_PIB_RESP_SHIFT; - *value =3D ind_data & XSCOM_DATA_IND_DATA; + rc =3D __get_scom(scom, &ind_data, addr, status); + if (rc || (*status & SCOM_STATUS_ANY_ERR)) + return rc; =20 - if ((ind_data & XSCOM_DATA_IND_COMPLETE) || (err !=3D SCOM_PIB_BLOCKED)) - return 0; + err =3D (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT; + *status =3D err << SCOM_STATUS_PIB_RESP_SHIFT; + *value =3D ind_data & XSCOM_DATA_IND_DATA; =20 - msleep(1); - } - return rc; + return 0; } =20 static int raw_put_scom(struct scom_device *scom, uint64_t value, @@ -289,7 +278,7 @@ static int put_scom(struct scom_device *scom, uint64_t = value, int rc; =20 rc =3D raw_put_scom(scom, value, addr, &status); - if (rc =3D=3D -ENODEV) + if (rc) return rc; =20 rc =3D handle_fsi2pib_status(scom, status); @@ -308,7 +297,7 @@ static int get_scom(struct scom_device *scom, uint64_t = *value, int rc; =20 rc =3D raw_get_scom(scom, value, addr, &status); - if (rc =3D=3D -ENODEV) + if (rc) return rc; =20 rc =3D handle_fsi2pib_status(scom, status); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/d= rm/amd/amdgpu/amdgpu_connectors.c index df1f9b88a53f..a09876bb7ec8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -175,7 +175,7 @@ int amdgpu_connector_get_monitor_bpc(struct drm_connect= or *connector) =20 /* Check if bpc is within clock limit. Try to degrade gracefully otherw= ise */ if ((bpc =3D=3D 12) && (mode_clock * 3/2 > max_tmds_clock)) { - if ((connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30)= && + if ((connector->display_info.edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI= _DC_30) && (mode_clock * 5/4 <=3D max_tmds_clock)) bpc =3D 10; else diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/a= md/amdgpu/amdgpu_device.c index 694c3726e0f4..6be480939d3f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -30,6 +30,7 @@ #include #include #include +#include =20 #include #include @@ -2070,6 +2071,8 @@ static int amdgpu_device_parse_gpu_info_fw(struct amd= gpu_device *adev) */ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) { + struct drm_device *dev =3D adev_to_drm(adev); + struct pci_dev *parent; int i, r; =20 amdgpu_device_enable_virtual_display(adev); @@ -2134,6 +2137,18 @@ static int amdgpu_device_ip_early_init(struct amdgpu= _device *adev) break; } =20 + if (amdgpu_has_atpx() && + (amdgpu_is_atpx_hybrid() || + amdgpu_has_atpx_dgpu_power_cntl()) && + ((adev->flags & AMD_IS_APU) =3D=3D 0) && + !pci_is_thunderbolt_attached(to_pci_dev(dev->dev))) + adev->flags |=3D AMD_IS_PX; + + if (!(adev->flags & AMD_IS_APU)) { + parent =3D pci_upstream_bridge(adev->pdev); + adev->has_pr3 =3D parent ? pci_pr3_present(parent) : false; + } + amdgpu_amdkfd_device_probe(adev); =20 adev->pm.pp_feature =3D amdgpu_pp_feature_mask; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/= amdgpu/amdgpu_kms.c index 09ad17944eb2..704702fef257 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -152,21 +152,10 @@ static void amdgpu_get_audio_func(struct amdgpu_devic= e *adev) int amdgpu_driver_load_kms(struct amdgpu_device *adev, unsigned long flags) { struct drm_device *dev; - struct pci_dev *parent; int r, acpi_status; =20 dev =3D adev_to_drm(adev); =20 - if (amdgpu_has_atpx() && - (amdgpu_is_atpx_hybrid() || - amdgpu_has_atpx_dgpu_power_cntl()) && - ((flags & AMD_IS_APU) =3D=3D 0) && - !pci_is_thunderbolt_attached(to_pci_dev(dev->dev))) - flags |=3D AMD_IS_PX; - - parent =3D pci_upstream_bridge(adev->pdev); - adev->has_pr3 =3D parent ? pci_pr3_present(parent) : false; - /* amdgpu_device_init should report only fatal error * like memory allocation failure or iomapping failure, * or memory manager initialization failure, it must diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gp= u/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 7a5bb5a3456a..7cadb9e81d9d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -8030,6 +8030,9 @@ static void amdgpu_dm_connector_add_common_modes(stru= ct drm_encoder *encoder, mode =3D amdgpu_dm_create_common_mode(encoder, common_modes[i].name, common_modes[i].w, common_modes[i].h); + if (!mode) + continue; + drm_mode_probed_add(connector, mode); amdgpu_dm_connector->num_modes++; } @@ -10749,10 +10752,13 @@ static int dm_check_crtc_cursor(struct drm_atomic= _state *state, static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, stru= ct drm_crtc *crtc) { struct drm_connector *connector; - struct drm_connector_state *conn_state; + struct drm_connector_state *conn_state, *old_conn_state; struct amdgpu_dm_connector *aconnector =3D NULL; int i; - for_each_new_connector_in_state(state, connector, conn_state, i) { + for_each_oldnew_connector_in_state(state, connector, old_conn_state, conn= _state, i) { + if (!conn_state->crtc) + conn_state =3D old_conn_state; + if (conn_state->crtc !=3D crtc) continue; =20 diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c b= /drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c index ed54e1c819be..a728087b3f3d 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c @@ -266,14 +266,6 @@ static const struct irq_source_info_funcs vline0_irq_i= nfo_funcs =3D { .funcs =3D &pflip_irq_info_funcs\ } =20 -#define vupdate_int_entry(reg_num)\ - [DC_IRQ_SOURCE_VUPDATE1 + reg_num] =3D {\ - IRQ_REG_ENTRY(OTG, reg_num,\ - OTG_GLOBAL_SYNC_STATUS, VUPDATE_INT_EN,\ - OTG_GLOBAL_SYNC_STATUS, VUPDATE_EVENT_CLEAR),\ - .funcs =3D &vblank_irq_info_funcs\ - } - /* vupdate_no_lock_int_entry maps to DC_IRQ_SOURCE_VUPDATEx, to match sema= ntic * of DCE's DC_IRQ_SOURCE_VUPDATEx. */ @@ -402,12 +394,6 @@ irq_source_info_dcn21[DAL_IRQ_SOURCES_NUMBER] =3D { dc_underflow_int_entry(6), [DC_IRQ_SOURCE_DMCU_SCP] =3D dummy_irq_entry(), [DC_IRQ_SOURCE_VBIOS_SW] =3D dummy_irq_entry(), - vupdate_int_entry(0), - vupdate_int_entry(1), - vupdate_int_entry(2), - vupdate_int_entry(3), - vupdate_int_entry(4), - vupdate_int_entry(5), vupdate_no_lock_int_entry(0), vupdate_no_lock_int_entry(1), vupdate_no_lock_int_entry(2), diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/am= dgpu_pm.c index d31719b3418f..8744bda59474 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -2123,8 +2123,8 @@ static int default_attr_update(struct amdgpu_device *= adev, struct amdgpu_device_ } } =20 - /* setting should not be allowed from VF */ - if (amdgpu_sriov_vf(adev)) { + /* setting should not be allowed from VF if not in one VF mode */ + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) { dev_attr->attr.mode &=3D ~S_IWUGO; dev_attr->store =3D NULL; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/am= d/pm/swsmu/amdgpu_smu.c index 9d7d64fdf410..9b54c1b89ea4 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -138,7 +138,7 @@ int smu_get_dpm_freq_range(struct smu_context *smu, uint32_t *min, uint32_t *max) { - int ret =3D 0; + int ret =3D -ENOTSUPP; =20 if (!min && !max) return -EINVAL; diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bri= dge/adv7511/adv7511.h index 05e3abb5a0c9..1b00dfda6e0d 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h @@ -169,6 +169,7 @@ #define ADV7511_PACKET_ENABLE_SPARE2 BIT(1) #define ADV7511_PACKET_ENABLE_SPARE1 BIT(0) =20 +#define ADV7535_REG_POWER2_HPD_OVERRIDE BIT(6) #define ADV7511_REG_POWER2_HPD_SRC_MASK 0xc0 #define ADV7511_REG_POWER2_HPD_SRC_BOTH 0x00 #define ADV7511_REG_POWER2_HPD_SRC_HPD 0x40 diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm= /bridge/adv7511/adv7511_drv.c index 76555ae64e9c..c02f3ec60b04 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -351,11 +351,17 @@ static void __adv7511_power_on(struct adv7511 *adv751= 1) * from standby or are enabled. When the HPD goes low the adv7511 is * reset and the outputs are disabled which might cause the monitor to * go to standby again. To avoid this we ignore the HPD pin for the - * first few seconds after enabling the output. + * first few seconds after enabling the output. On the other hand + * adv7535 require to enable HPD Override bit for proper HPD. */ - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, - ADV7511_REG_POWER2_HPD_SRC_MASK, - ADV7511_REG_POWER2_HPD_SRC_NONE); + if (adv7511->type =3D=3D ADV7535) + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, + ADV7535_REG_POWER2_HPD_OVERRIDE, + ADV7535_REG_POWER2_HPD_OVERRIDE); + else + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, + ADV7511_REG_POWER2_HPD_SRC_MASK, + ADV7511_REG_POWER2_HPD_SRC_NONE); } =20 static void adv7511_power_on(struct adv7511 *adv7511) @@ -375,6 +381,10 @@ static void adv7511_power_on(struct adv7511 *adv7511) static void __adv7511_power_off(struct adv7511 *adv7511) { /* TODO: setup additional power down modes */ + if (adv7511->type =3D=3D ADV7535) + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, + ADV7535_REG_POWER2_HPD_OVERRIDE, 0); + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, ADV7511_POWER_POWER_DOWN, ADV7511_POWER_POWER_DOWN); @@ -672,9 +682,14 @@ adv7511_detect(struct adv7511 *adv7511, struct drm_con= nector *connector) status =3D connector_status_disconnected; } else { /* Renable HPD sensing */ - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, - ADV7511_REG_POWER2_HPD_SRC_MASK, - ADV7511_REG_POWER2_HPD_SRC_BOTH); + if (adv7511->type =3D=3D ADV7535) + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, + ADV7535_REG_POWER2_HPD_OVERRIDE, + ADV7535_REG_POWER2_HPD_OVERRIDE); + else + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, + ADV7511_REG_POWER2_HPD_SRC_MASK, + ADV7511_REG_POWER2_HPD_SRC_BOTH); } =20 adv7511->status =3D status; diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/br= idge/analogix/anx7625.c index 1a871f6b6822..9b2421040926 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -791,7 +791,8 @@ static int segments_edid_read(struct anx7625_data *ctx, static int sp_tx_edid_read(struct anx7625_data *ctx, u8 *pedid_blocks_buf) { - u8 offset, edid_pos; + u8 offset; + int edid_pos; int count, blocks_num; u8 pblock_buf[MAX_DPCD_BUFFER_SIZE]; u8 i, j; diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdn= s-dsi.c index d8a15c459b42..829e1a144656 100644 --- a/drivers/gpu/drm/bridge/cdns-dsi.c +++ b/drivers/gpu/drm/bridge/cdns-dsi.c @@ -1284,6 +1284,7 @@ static const struct of_device_id cdns_dsi_of_match[] = =3D { { .compatible =3D "cdns,dsi" }, { }, }; +MODULE_DEVICE_TABLE(of, cdns_dsi_of_match); =20 static struct platform_driver cdns_dsi_platform_driver =3D { .probe =3D cdns_dsi_drm_probe, diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-= dsi.c index af07eeb47ca0..6e484d836cfe 100644 --- a/drivers/gpu/drm/bridge/nwl-dsi.c +++ b/drivers/gpu/drm/bridge/nwl-dsi.c @@ -1204,6 +1204,7 @@ static int nwl_dsi_probe(struct platform_device *pdev) =20 ret =3D nwl_dsi_select_input(dsi); if (ret < 0) { + pm_runtime_disable(dev); mipi_dsi_host_unregister(&dsi->dsi_host); return ret; } diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/= sil-sii8620.c index 843265d7f1b1..ec7745c31da0 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c @@ -2120,7 +2120,7 @@ static void sii8620_init_rcp_input_dev(struct sii8620= *ctx) if (ret) { dev_err(ctx->dev, "Failed to register RC device\n"); ctx->error =3D ret; - rc_free_device(ctx->rc_dev); + rc_free_device(rc_dev); return; } ctx->rc_dev =3D rc_dev; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/br= idge/synopsys/dw-hdmi.c index e1211a5b334b..25d58dcfc87e 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -2551,8 +2551,9 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts= (struct drm_bridge *bridge, if (!output_fmts) return NULL; =20 - /* If dw-hdmi is the only bridge, avoid negociating with ourselves */ - if (list_is_singular(&bridge->encoder->bridge_chain)) { + /* If dw-hdmi is the first or only bridge, avoid negociating with ourselv= es */ + if (list_is_singular(&bridge->encoder->bridge_chain) || + list_is_first(&bridge->chain_node, &bridge->encoder->bridge_chain)) { *num_output_fmts =3D 1; output_fmts[0] =3D MEDIA_BUS_FMT_FIXED; =20 diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/dr= m/bridge/synopsys/dw-mipi-dsi.c index e44e18a0112a..56c3fd08c6a0 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -1199,6 +1199,7 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, ret =3D mipi_dsi_host_register(&dsi->dsi_host); if (ret) { dev_err(dev, "Failed to register MIPI host: %d\n", ret); + pm_runtime_disable(dev); dw_mipi_dsi_debugfs_remove(dsi); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index f5f5de362ff2..b8f5419e514a 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4848,7 +4848,8 @@ bool drm_detect_monitor_audio(struct edid *edid) if (!edid_ext) goto end; =20 - has_audio =3D ((edid_ext[3] & EDID_BASIC_AUDIO) !=3D 0); + has_audio =3D (edid_ext[0] =3D=3D CEA_EXT && + (edid_ext[3] & EDID_BASIC_AUDIO) !=3D 0); =20 if (has_audio) { DRM_DEBUG_KMS("Monitor has basic audio support\n"); @@ -5075,21 +5076,21 @@ static void drm_parse_hdmi_deep_color_info(struct d= rm_connector *connector, =20 if (hdmi[6] & DRM_EDID_HDMI_DC_30) { dc_bpc =3D 10; - info->edid_hdmi_dc_modes |=3D DRM_EDID_HDMI_DC_30; + info->edid_hdmi_rgb444_dc_modes |=3D DRM_EDID_HDMI_DC_30; DRM_DEBUG("%s: HDMI sink does deep color 30.\n", connector->name); } =20 if (hdmi[6] & DRM_EDID_HDMI_DC_36) { dc_bpc =3D 12; - info->edid_hdmi_dc_modes |=3D DRM_EDID_HDMI_DC_36; + info->edid_hdmi_rgb444_dc_modes |=3D DRM_EDID_HDMI_DC_36; DRM_DEBUG("%s: HDMI sink does deep color 36.\n", connector->name); } =20 if (hdmi[6] & DRM_EDID_HDMI_DC_48) { dc_bpc =3D 16; - info->edid_hdmi_dc_modes |=3D DRM_EDID_HDMI_DC_48; + info->edid_hdmi_rgb444_dc_modes |=3D DRM_EDID_HDMI_DC_48; DRM_DEBUG("%s: HDMI sink does deep color 48.\n", connector->name); } @@ -5104,16 +5105,9 @@ static void drm_parse_hdmi_deep_color_info(struct dr= m_connector *connector, connector->name, dc_bpc); info->bpc =3D dc_bpc; =20 - /* - * Deep color support mandates RGB444 support for all video - * modes and forbids YCRCB422 support for all video modes per - * HDMI 1.3 spec. - */ - info->color_formats =3D DRM_COLOR_FORMAT_RGB444; - /* YCRCB444 is optional according to spec. */ if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) { - info->color_formats |=3D DRM_COLOR_FORMAT_YCRCB444; + info->edid_hdmi_ycbcr444_dc_modes =3D info->edid_hdmi_rgb444_dc_modes; DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n", connector->name); } diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helpe= r.c index 22bf690910b2..ed589e7182bb 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -2346,6 +2346,7 @@ static int drm_fb_helper_generic_probe(struct drm_fb_= helper *fb_helper, fbi->fbops =3D &drm_fbdev_fb_ops; fbi->screen_size =3D fb->height * fb->pitches[0]; fbi->fix.smem_len =3D fbi->screen_size; + fbi->flags =3D FBINFO_DEFAULT; =20 drm_fb_helper_fill_info(fbi, fb_helper, sizes); =20 @@ -2353,19 +2354,21 @@ static int drm_fb_helper_generic_probe(struct drm_f= b_helper *fb_helper, fbi->screen_buffer =3D vzalloc(fbi->screen_size); if (!fbi->screen_buffer) return -ENOMEM; + fbi->flags |=3D FBINFO_VIRTFB | FBINFO_READS_FAST; =20 fbi->fbdefio =3D &drm_fbdev_defio; - fb_deferred_io_init(fbi); } else { /* buffer is mapped for HW framebuffer */ ret =3D drm_client_buffer_vmap(fb_helper->buffer, &map); if (ret) return ret; - if (map.is_iomem) + if (map.is_iomem) { fbi->screen_base =3D map.vaddr_iomem; - else + } else { fbi->screen_buffer =3D map.vaddr; + fbi->flags |=3D FBINFO_VIRTFB; + } =20 /* * Shamelessly leak the physical address to user-space. As diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index c313a5b4549c..7e48dcd1bee4 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -853,12 +853,57 @@ drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev= , void *data, &args->handle); } =20 + +/* + * Try to flatten a dma_fence_chain into a dma_fence_array so that it can = be + * added as timeline fence to a chain again. + */ +static int drm_syncobj_flatten_chain(struct dma_fence **f) +{ + struct dma_fence_chain *chain =3D to_dma_fence_chain(*f); + struct dma_fence *tmp, **fences; + struct dma_fence_array *array; + unsigned int count; + + if (!chain) + return 0; + + count =3D 0; + dma_fence_chain_for_each(tmp, &chain->base) + ++count; + + fences =3D kmalloc_array(count, sizeof(*fences), GFP_KERNEL); + if (!fences) + return -ENOMEM; + + count =3D 0; + dma_fence_chain_for_each(tmp, &chain->base) + fences[count++] =3D dma_fence_get(tmp); + + array =3D dma_fence_array_create(count, fences, + dma_fence_context_alloc(1), + 1, false); + if (!array) + goto free_fences; + + dma_fence_put(*f); + *f =3D &array->base; + return 0; + +free_fences: + while (count--) + dma_fence_put(fences[count]); + + kfree(fences); + return -ENOMEM; +} + static int drm_syncobj_transfer_to_timeline(struct drm_file *file_private, struct drm_syncobj_transfer *args) { struct drm_syncobj *timeline_syncobj =3D NULL; - struct dma_fence *fence; struct dma_fence_chain *chain; + struct dma_fence *fence; int ret; =20 timeline_syncobj =3D drm_syncobj_find(file_private, args->dst_handle); @@ -869,16 +914,22 @@ static int drm_syncobj_transfer_to_timeline(struct dr= m_file *file_private, args->src_point, args->flags, &fence); if (ret) - goto err; + goto err_put_timeline; + + ret =3D drm_syncobj_flatten_chain(&fence); + if (ret) + goto err_free_fence; + chain =3D dma_fence_chain_alloc(); if (!chain) { ret =3D -ENOMEM; - goto err1; + goto err_free_fence; } + drm_syncobj_add_point(timeline_syncobj, chain, fence, args->dst_point); -err1: +err_free_fence: dma_fence_put(fence); -err: +err_put_timeline: drm_syncobj_put(timeline_syncobj); =20 return ret; diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915= /display/intel_bw.c index 5a2f96d39ac7..8f0f1c63a353 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -819,7 +819,8 @@ int intel_bw_atomic_check(struct intel_atomic_state *st= ate) * cause. */ if (!intel_can_enable_sagv(dev_priv, new_bw_state)) { - allowed_points =3D BIT(max_bw_point); + allowed_points &=3D ADLS_PSF_PT_MASK; + allowed_points |=3D BIT(max_bw_point); drm_dbg_kms(&dev_priv->drm, "No SAGV, using single QGV point %d\n", max_bw_point); } diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915= /display/intel_dp.c index a552f05a67e5..3ee0f2fc9c21 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -4742,7 +4742,7 @@ intel_dp_hpd_pulse(struct intel_digital_port *dig_por= t, bool long_hpd) struct intel_dp *intel_dp =3D &dig_port->dp; =20 if (dig_port->base.type =3D=3D INTEL_OUTPUT_EDP && - (long_hpd || !intel_pps_have_power(intel_dp))) { + (long_hpd || !intel_pps_have_panel_power_or_vdd(intel_dp))) { /* * vdd off can generate a long/short pulse on eDP which * would require vdd on to handle it, and thus we diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i9= 15/display/intel_hdmi.c index 371736bdc01f..2ca9b90557a2 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -1831,6 +1831,7 @@ hdmi_port_clock_valid(struct intel_hdmi *hdmi, bool has_hdmi_sink) { struct drm_i915_private *dev_priv =3D intel_hdmi_to_i915(hdmi); + enum phy phy =3D intel_port_to_phy(dev_priv, hdmi_to_dig_port(hdmi)->base= .port); =20 if (clock < 25000) return MODE_CLOCK_LOW; @@ -1851,6 +1852,14 @@ hdmi_port_clock_valid(struct intel_hdmi *hdmi, if (IS_CHERRYVIEW(dev_priv) && clock > 216000 && clock < 240000) return MODE_CLOCK_RANGE; =20 + /* ICL+ combo PHY PLL can't generate 500-533.2 MHz */ + if (intel_phy_is_combo(dev_priv, phy) && clock > 500000 && clock < 533200) + return MODE_CLOCK_RANGE; + + /* ICL+ TC PHY PLL can't generate 500-532.8 MHz */ + if (intel_phy_is_tc(dev_priv, phy) && clock > 500000 && clock < 532800) + return MODE_CLOCK_RANGE; + /* * SNPS PHYs' MPLLB table-based programming can only handle a fixed * set of link rates. @@ -1892,7 +1901,7 @@ static bool intel_hdmi_bpc_possible(struct drm_connec= tor *connector, if (ycbcr420_output) return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_36; else - return info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_36; + return info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36; case 10: if (DISPLAY_VER(i915) < 11) return false; @@ -1903,7 +1912,7 @@ static bool intel_hdmi_bpc_possible(struct drm_connec= tor *connector, if (ycbcr420_output) return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_30; else - return info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30; + return info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30; case 8: return true; default: diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/dr= m/i915/display/intel_opregion.c index 4a2662838cd8..df10b6898987 100644 --- a/drivers/gpu/drm/i915/display/intel_opregion.c +++ b/drivers/gpu/drm/i915/display/intel_opregion.c @@ -375,6 +375,21 @@ int intel_opregion_notify_encoder(struct intel_encoder= *intel_encoder, return -EINVAL; } =20 + /* + * The port numbering and mapping here is bizarre. The now-obsolete + * swsci spec supports ports numbered [0..4]. Port E is handled as a + * special case, but port F and beyond are not. The functionality is + * supposed to be obsolete for new platforms. Just bail out if the port + * number is out of bounds after mapping. + */ + if (port > 4) { + drm_dbg_kms(&dev_priv->drm, + "[ENCODER:%d:%s] port %c (index %u) out of bounds for display power= state notification\n", + intel_encoder->base.base.id, intel_encoder->base.name, + port_name(intel_encoder->port), port); + return -EINVAL; + } + if (!enable) parm |=3D 4 << 8; =20 diff --git a/drivers/gpu/drm/i915/display/intel_pps.c b/drivers/gpu/drm/i91= 5/display/intel_pps.c index e9c679bb1b2e..5edd188d9747 100644 --- a/drivers/gpu/drm/i915/display/intel_pps.c +++ b/drivers/gpu/drm/i915/display/intel_pps.c @@ -1075,14 +1075,14 @@ static void intel_pps_vdd_sanitize(struct intel_dp = *intel_dp) edp_panel_vdd_schedule_off(intel_dp); } =20 -bool intel_pps_have_power(struct intel_dp *intel_dp) +bool intel_pps_have_panel_power_or_vdd(struct intel_dp *intel_dp) { intel_wakeref_t wakeref; bool have_power =3D false; =20 with_intel_pps_lock(intel_dp, wakeref) { - have_power =3D edp_have_panel_power(intel_dp) && - edp_have_panel_vdd(intel_dp); + have_power =3D edp_have_panel_power(intel_dp) || + edp_have_panel_vdd(intel_dp); } =20 return have_power; diff --git a/drivers/gpu/drm/i915/display/intel_pps.h b/drivers/gpu/drm/i91= 5/display/intel_pps.h index fbb47f6f453e..e64144659d31 100644 --- a/drivers/gpu/drm/i915/display/intel_pps.h +++ b/drivers/gpu/drm/i915/display/intel_pps.h @@ -37,7 +37,7 @@ void intel_pps_vdd_on(struct intel_dp *intel_dp); void intel_pps_on(struct intel_dp *intel_dp); void intel_pps_off(struct intel_dp *intel_dp); void intel_pps_vdd_off_sync(struct intel_dp *intel_dp); -bool intel_pps_have_power(struct intel_dp *intel_dp); +bool intel_pps_have_panel_power_or_vdd(struct intel_dp *intel_dp); void intel_pps_wait_power_cycle(struct intel_dp *intel_dp); =20 void intel_pps_init(struct intel_dp *intel_dp); diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i91= 5/display/intel_psr.c index 3ba8b717e176..f7ade9c06386 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1793,6 +1793,9 @@ static void _intel_psr_post_plane_update(const struct= intel_atomic_state *state, =20 mutex_lock(&psr->lock); =20 + if (psr->sink_not_reliable) + goto exit; + drm_WARN_ON(&dev_priv->drm, psr->enabled && !crtc_state->active_planes); =20 /* Only enable if there is active planes */ @@ -1803,6 +1806,7 @@ static void _intel_psr_post_plane_update(const struct= intel_atomic_state *state, if (crtc_state->crc_enabled && psr->enabled) psr_force_hw_tracking_exit(intel_dp); =20 +exit: mutex_unlock(&psr->lock); } } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.c b/drivers/gpu/drm/i91= 5/gem/i915_gem_mman.c index 65fc6ff5f59d..9be5678becd0 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.c @@ -438,7 +438,7 @@ vm_access(struct vm_area_struct *area, unsigned long ad= dr, return -EACCES; =20 addr -=3D area->vm_start; - if (addr >=3D obj->base.size) + if (range_overflows_t(u64, addr, len, obj->base.size)) return -EINVAL; =20 i915_gem_ww_ctx_init(&ww, true); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_p= m.c index 7cbffd9a7be8..db95ed16749e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3712,8 +3712,7 @@ skl_setup_sagv_block_time(struct drm_i915_private *de= v_priv) MISSING_CASE(DISPLAY_VER(dev_priv)); } =20 - /* Default to an unusable block time */ - dev_priv->sagv_block_time_us =3D -1; + dev_priv->sagv_block_time_us =3D 0; } =20 /* @@ -5634,7 +5633,7 @@ static void skl_compute_plane_wm(const struct intel_c= rtc_state *crtc_state, result->min_ddb_alloc =3D max(min_ddb_alloc, blocks) + 1; result->enable =3D true; =20 - if (DISPLAY_VER(dev_priv) < 12) + if (DISPLAY_VER(dev_priv) < 12 && dev_priv->sagv_block_time_us) result->can_sagv =3D latency >=3D dev_priv->sagv_block_time_us; } =20 @@ -5665,7 +5664,10 @@ static void tgl_compute_sagv_wm(const struct intel_c= rtc_state *crtc_state, struct drm_i915_private *dev_priv =3D to_i915(crtc_state->uapi.crtc->dev); struct skl_wm_level *sagv_wm =3D &plane_wm->sagv.wm0; struct skl_wm_level *levels =3D plane_wm->wm; - unsigned int latency =3D dev_priv->wm.skl_latency[0] + dev_priv->sagv_blo= ck_time_us; + unsigned int latency =3D 0; + + if (dev_priv->sagv_block_time_us) + latency =3D dev_priv->sagv_block_time_us + dev_priv->wm.skl_latency[0]; =20 skl_compute_plane_wm(crtc_state, 0, latency, wm_params, &levels[0], diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile index 28a519cdf66b..523fce45f16b 100644 --- a/drivers/gpu/drm/meson/Makefile +++ b/drivers/gpu/drm/meson/Makefile @@ -2,6 +2,7 @@ meson-drm-y :=3D meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o meson-drm-y +=3D meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_o= verlay.o meson-drm-y +=3D meson_rdma.o meson_osd_afbcd.o +meson-drm-y +=3D meson_encoder_hdmi.o =20 obj-$(CONFIG_DRM_MESON) +=3D meson-drm.o obj-$(CONFIG_DRM_MESON_DW_HDMI) +=3D meson_dw_hdmi.o diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meso= n_drv.c index 7f41a33592c8..c98525d60df5 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -32,6 +32,7 @@ #include "meson_osd_afbcd.h" #include "meson_registers.h" #include "meson_venc_cvbs.h" +#include "meson_encoder_hdmi.h" #include "meson_viu.h" #include "meson_vpp.h" #include "meson_rdma.h" @@ -301,38 +302,42 @@ static int meson_drv_bind_master(struct device *dev, = bool has_components) if (priv->afbcd.ops) { ret =3D priv->afbcd.ops->init(priv); if (ret) - return ret; + goto free_drm; } =20 /* Encoder Initialization */ =20 ret =3D meson_venc_cvbs_create(priv); if (ret) - goto free_drm; + goto exit_afbcd; =20 if (has_components) { ret =3D component_bind_all(drm->dev, drm); if (ret) { dev_err(drm->dev, "Couldn't bind all components\n"); - goto free_drm; + goto exit_afbcd; } } =20 + ret =3D meson_encoder_hdmi_init(priv); + if (ret) + goto exit_afbcd; + ret =3D meson_plane_create(priv); if (ret) - goto free_drm; + goto exit_afbcd; =20 ret =3D meson_overlay_create(priv); if (ret) - goto free_drm; + goto exit_afbcd; =20 ret =3D meson_crtc_create(priv); if (ret) - goto free_drm; + goto exit_afbcd; =20 ret =3D request_irq(priv->vsync_irq, meson_irq, 0, drm->driver->name, drm= ); if (ret) - goto free_drm; + goto exit_afbcd; =20 drm_mode_config_reset(drm); =20 @@ -350,6 +355,9 @@ static int meson_drv_bind_master(struct device *dev, bo= ol has_components) =20 uninstall_irq: free_irq(priv->vsync_irq, drm); +exit_afbcd: + if (priv->afbcd.ops) + priv->afbcd.ops->exit(priv); free_drm: drm_dev_put(drm); =20 @@ -380,10 +388,8 @@ static void meson_drv_unbind(struct device *dev) free_irq(priv->vsync_irq, drm); drm_dev_put(drm); =20 - if (priv->afbcd.ops) { - priv->afbcd.ops->reset(priv); - meson_rdma_free(priv); - } + if (priv->afbcd.ops) + priv->afbcd.ops->exit(priv); } =20 static const struct component_master_ops meson_drv_master_ops =3D { diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/= meson_dw_hdmi.c index 0afbd1e70bfc..fb540a503efe 100644 --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c @@ -22,14 +22,11 @@ #include #include =20 -#include #include =20 #include "meson_drv.h" #include "meson_dw_hdmi.h" #include "meson_registers.h" -#include "meson_vclk.h" -#include "meson_venc.h" =20 #define DRIVER_NAME "meson-dw-hdmi" #define DRIVER_DESC "Amlogic Meson HDMI-TX DRM driver" @@ -135,8 +132,6 @@ struct meson_dw_hdmi_data { }; =20 struct meson_dw_hdmi { - struct drm_encoder encoder; - struct drm_bridge bridge; struct dw_hdmi_plat_data dw_plat_data; struct meson_drm *priv; struct device *dev; @@ -148,12 +143,8 @@ struct meson_dw_hdmi { struct regulator *hdmi_supply; u32 irq_stat; struct dw_hdmi *hdmi; - unsigned long output_bus_fmt; + struct drm_bridge *bridge; }; -#define encoder_to_meson_dw_hdmi(x) \ - container_of(x, struct meson_dw_hdmi, encoder) -#define bridge_to_meson_dw_hdmi(x) \ - container_of(x, struct meson_dw_hdmi, bridge) =20 static inline int dw_hdmi_is_compatible(struct meson_dw_hdmi *dw_hdmi, const char *compat) @@ -295,14 +286,14 @@ static inline void dw_hdmi_dwc_write_bits(struct meso= n_dw_hdmi *dw_hdmi, =20 /* Setup PHY bandwidth modes */ static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi, - const struct drm_display_mode *mode) + const struct drm_display_mode *mode, + bool mode_is_420) { struct meson_drm *priv =3D dw_hdmi->priv; unsigned int pixel_clock =3D mode->clock; =20 /* For 420, pixel clock is half unlike venc clock */ - if (dw_hdmi->output_bus_fmt =3D=3D MEDIA_BUS_FMT_UYYVYY8_0_5X24) - pixel_clock /=3D 2; + if (mode_is_420) pixel_clock /=3D 2; =20 if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) { @@ -374,68 +365,25 @@ static inline void meson_dw_hdmi_phy_reset(struct mes= on_dw_hdmi *dw_hdmi) mdelay(2); } =20 -static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi, - const struct drm_display_mode *mode) -{ - struct meson_drm *priv =3D dw_hdmi->priv; - int vic =3D drm_match_cea_mode(mode); - unsigned int phy_freq; - unsigned int vclk_freq; - unsigned int venc_freq; - unsigned int hdmi_freq; - - vclk_freq =3D mode->clock; - - /* For 420, pixel clock is half unlike venc clock */ - if (dw_hdmi->output_bus_fmt =3D=3D MEDIA_BUS_FMT_UYYVYY8_0_5X24) - vclk_freq /=3D 2; - - /* TMDS clock is pixel_clock * 10 */ - phy_freq =3D vclk_freq * 10; - - if (!vic) { - meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, phy_freq, - vclk_freq, vclk_freq, vclk_freq, false); - return; - } - - /* 480i/576i needs global pixel doubling */ - if (mode->flags & DRM_MODE_FLAG_DBLCLK) - vclk_freq *=3D 2; - - venc_freq =3D vclk_freq; - hdmi_freq =3D vclk_freq; - - /* VENC double pixels for 1080i, 720p and YUV420 modes */ - if (meson_venc_hdmi_venc_repeat(vic) || - dw_hdmi->output_bus_fmt =3D=3D MEDIA_BUS_FMT_UYYVYY8_0_5X24) - venc_freq *=3D 2; - - vclk_freq =3D max(venc_freq, hdmi_freq); - - if (mode->flags & DRM_MODE_FLAG_DBLCLK) - venc_freq /=3D 2; - - DRM_DEBUG_DRIVER("vclk:%d phy=3D%d venc=3D%d hdmi=3D%d enci=3D%d\n", - phy_freq, vclk_freq, venc_freq, hdmi_freq, - priv->venc.hdmi_use_enci); - - meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, phy_freq, vclk_freq, - venc_freq, hdmi_freq, priv->venc.hdmi_use_enci); -} - static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, const struct drm_display_info *display, const struct drm_display_mode *mode) { struct meson_dw_hdmi *dw_hdmi =3D (struct meson_dw_hdmi *)data; + bool is_hdmi2_sink =3D display->hdmi.scdc.supported; struct meson_drm *priv =3D dw_hdmi->priv; unsigned int wr_clk =3D readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING)); + bool mode_is_420 =3D false; =20 DRM_DEBUG_DRIVER("\"%s\" div%d\n", mode->name, mode->clock > 340000 ? 40 : 10); =20 + if (drm_mode_is_420_only(display, mode) || + (!is_hdmi2_sink && + drm_mode_is_420_also(display, mode))) + mode_is_420 =3D true; + /* Enable clocks */ regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100); =20 @@ -457,8 +405,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void = *data, dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); =20 /* TMDS pattern setup */ - if (mode->clock > 340000 && - dw_hdmi->output_bus_fmt =3D=3D MEDIA_BUS_FMT_YUV8_1X24) { + if (mode->clock > 340000 && !mode_is_420) { dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0); dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, @@ -476,7 +423,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void = *data, dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2); =20 /* Setup PHY parameters */ - meson_hdmi_phy_setup_mode(dw_hdmi, mode); + meson_hdmi_phy_setup_mode(dw_hdmi, mode, mode_is_420); =20 /* Setup PHY */ regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, @@ -622,214 +569,15 @@ static irqreturn_t dw_hdmi_top_thread_irq(int irq, v= oid *dev_id) dw_hdmi_setup_rx_sense(dw_hdmi->hdmi, hpd_connected, hpd_connected); =20 - drm_helper_hpd_irq_event(dw_hdmi->encoder.dev); + drm_helper_hpd_irq_event(dw_hdmi->bridge->dev); + drm_bridge_hpd_notify(dw_hdmi->bridge, + hpd_connected ? connector_status_connected + : connector_status_disconnected); } =20 return IRQ_HANDLED; } =20 -static enum drm_mode_status -dw_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, - const struct drm_display_info *display_info, - const struct drm_display_mode *mode) -{ - struct meson_dw_hdmi *dw_hdmi =3D data; - struct meson_drm *priv =3D dw_hdmi->priv; - bool is_hdmi2_sink =3D display_info->hdmi.scdc.supported; - unsigned int phy_freq; - unsigned int vclk_freq; - unsigned int venc_freq; - unsigned int hdmi_freq; - int vic =3D drm_match_cea_mode(mode); - enum drm_mode_status status; - - DRM_DEBUG_DRIVER("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); - - /* If sink does not support 540MHz, reject the non-420 HDMI2 modes */ - if (display_info->max_tmds_clock && - mode->clock > display_info->max_tmds_clock && - !drm_mode_is_420_only(display_info, mode) && - !drm_mode_is_420_also(display_info, mode)) - return MODE_BAD; - - /* Check against non-VIC supported modes */ - if (!vic) { - status =3D meson_venc_hdmi_supported_mode(mode); - if (status !=3D MODE_OK) - return status; - - return meson_vclk_dmt_supported_freq(priv, mode->clock); - /* Check against supported VIC modes */ - } else if (!meson_venc_hdmi_supported_vic(vic)) - return MODE_BAD; - - vclk_freq =3D mode->clock; - - /* For 420, pixel clock is half unlike venc clock */ - if (drm_mode_is_420_only(display_info, mode) || - (!is_hdmi2_sink && - drm_mode_is_420_also(display_info, mode))) - vclk_freq /=3D 2; - - /* TMDS clock is pixel_clock * 10 */ - phy_freq =3D vclk_freq * 10; - - /* 480i/576i needs global pixel doubling */ - if (mode->flags & DRM_MODE_FLAG_DBLCLK) - vclk_freq *=3D 2; - - venc_freq =3D vclk_freq; - hdmi_freq =3D vclk_freq; - - /* VENC double pixels for 1080i, 720p and YUV420 modes */ - if (meson_venc_hdmi_venc_repeat(vic) || - drm_mode_is_420_only(display_info, mode) || - (!is_hdmi2_sink && - drm_mode_is_420_also(display_info, mode))) - venc_freq *=3D 2; - - vclk_freq =3D max(venc_freq, hdmi_freq); - - if (mode->flags & DRM_MODE_FLAG_DBLCLK) - venc_freq /=3D 2; - - dev_dbg(dw_hdmi->dev, "%s: vclk:%d phy=3D%d venc=3D%d hdmi=3D%d\n", - __func__, phy_freq, vclk_freq, venc_freq, hdmi_freq); - - return meson_vclk_vic_supported_freq(priv, phy_freq, vclk_freq); -} - -/* Encoder */ - -static const u32 meson_dw_hdmi_out_bus_fmts[] =3D { - MEDIA_BUS_FMT_YUV8_1X24, - MEDIA_BUS_FMT_UYYVYY8_0_5X24, -}; - -static void meson_venc_hdmi_encoder_destroy(struct drm_encoder *encoder) -{ - drm_encoder_cleanup(encoder); -} - -static const struct drm_encoder_funcs meson_venc_hdmi_encoder_funcs =3D { - .destroy =3D meson_venc_hdmi_encoder_destroy, -}; - -static u32 * -meson_venc_hdmi_encoder_get_inp_bus_fmts(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state, - u32 output_fmt, - unsigned int *num_input_fmts) -{ - u32 *input_fmts =3D NULL; - int i; - - *num_input_fmts =3D 0; - - for (i =3D 0 ; i < ARRAY_SIZE(meson_dw_hdmi_out_bus_fmts) ; ++i) { - if (output_fmt =3D=3D meson_dw_hdmi_out_bus_fmts[i]) { - *num_input_fmts =3D 1; - input_fmts =3D kcalloc(*num_input_fmts, - sizeof(*input_fmts), - GFP_KERNEL); - if (!input_fmts) - return NULL; - - input_fmts[0] =3D output_fmt; - - break; - } - } - - return input_fmts; -} - -static int meson_venc_hdmi_encoder_atomic_check(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - struct meson_dw_hdmi *dw_hdmi =3D bridge_to_meson_dw_hdmi(bridge); - - dw_hdmi->output_bus_fmt =3D bridge_state->output_bus_cfg.format; - - DRM_DEBUG_DRIVER("output_bus_fmt %lx\n", dw_hdmi->output_bus_fmt); - - return 0; -} - -static void meson_venc_hdmi_encoder_disable(struct drm_bridge *bridge) -{ - struct meson_dw_hdmi *dw_hdmi =3D bridge_to_meson_dw_hdmi(bridge); - struct meson_drm *priv =3D dw_hdmi->priv; - - DRM_DEBUG_DRIVER("\n"); - - writel_bits_relaxed(0x3, 0, - priv->io_base + _REG(VPU_HDMI_SETTING)); - - writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN)); - writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN)); -} - -static void meson_venc_hdmi_encoder_enable(struct drm_bridge *bridge) -{ - struct meson_dw_hdmi *dw_hdmi =3D bridge_to_meson_dw_hdmi(bridge); - struct meson_drm *priv =3D dw_hdmi->priv; - - DRM_DEBUG_DRIVER("%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP"); - - if (priv->venc.hdmi_use_enci) - writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN)); - else - writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN)); -} - -static void meson_venc_hdmi_encoder_mode_set(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - const struct drm_display_mode *adjusted_mode) -{ - struct meson_dw_hdmi *dw_hdmi =3D bridge_to_meson_dw_hdmi(bridge); - struct meson_drm *priv =3D dw_hdmi->priv; - int vic =3D drm_match_cea_mode(mode); - unsigned int ycrcb_map =3D VPU_HDMI_OUTPUT_CBYCR; - bool yuv420_mode =3D false; - - DRM_DEBUG_DRIVER("\"%s\" vic %d\n", mode->name, vic); - - if (dw_hdmi->output_bus_fmt =3D=3D MEDIA_BUS_FMT_UYYVYY8_0_5X24) { - ycrcb_map =3D VPU_HDMI_OUTPUT_CRYCB; - yuv420_mode =3D true; - } - - /* VENC + VENC-DVI Mode setup */ - meson_venc_hdmi_mode_set(priv, vic, ycrcb_map, yuv420_mode, mode); - - /* VCLK Set clock */ - dw_hdmi_set_vclk(dw_hdmi, mode); - - if (dw_hdmi->output_bus_fmt =3D=3D MEDIA_BUS_FMT_UYYVYY8_0_5X24) - /* Setup YUV420 to HDMI-TX, no 10bit diphering */ - writel_relaxed(2 | (2 << 2), - priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); - else - /* Setup YUV444 to HDMI-TX, no 10bit diphering */ - writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); -} - -static const struct drm_bridge_funcs meson_venc_hdmi_encoder_bridge_funcs = =3D { - .atomic_duplicate_state =3D drm_atomic_helper_bridge_duplicate_state, - .atomic_destroy_state =3D drm_atomic_helper_bridge_destroy_state, - .atomic_get_input_bus_fmts =3D meson_venc_hdmi_encoder_get_inp_bus_fmts, - .atomic_reset =3D drm_atomic_helper_bridge_reset, - .atomic_check =3D meson_venc_hdmi_encoder_atomic_check, - .enable =3D meson_venc_hdmi_encoder_enable, - .disable =3D meson_venc_hdmi_encoder_disable, - .mode_set =3D meson_venc_hdmi_encoder_mode_set, -}; - /* DW HDMI Regmap */ =20 static int meson_dw_hdmi_reg_read(void *context, unsigned int reg, @@ -876,28 +624,6 @@ static const struct meson_dw_hdmi_data meson_dw_hdmi_g= 12a_data =3D { .dwc_write =3D dw_hdmi_g12a_dwc_write, }; =20 -static bool meson_hdmi_connector_is_available(struct device *dev) -{ - struct device_node *ep, *remote; - - /* HDMI Connector is on the second port, first endpoint */ - ep =3D of_graph_get_endpoint_by_regs(dev->of_node, 1, 0); - if (!ep) - return false; - - /* If the endpoint node exists, consider it enabled */ - remote =3D of_graph_get_remote_port(ep); - if (remote) { - of_node_put(ep); - return true; - } - - of_node_put(ep); - of_node_put(remote); - - return false; -} - static void meson_dw_hdmi_init(struct meson_dw_hdmi *meson_dw_hdmi) { struct meson_drm *priv =3D meson_dw_hdmi->priv; @@ -976,18 +702,11 @@ static int meson_dw_hdmi_bind(struct device *dev, str= uct device *master, struct drm_device *drm =3D data; struct meson_drm *priv =3D drm->dev_private; struct dw_hdmi_plat_data *dw_plat_data; - struct drm_bridge *next_bridge; - struct drm_encoder *encoder; int irq; int ret; =20 DRM_DEBUG_DRIVER("\n"); =20 - if (!meson_hdmi_connector_is_available(dev)) { - dev_info(drm->dev, "HDMI Output connector not available\n"); - return -ENODEV; - } - match =3D of_device_get_match_data(&pdev->dev); if (!match) { dev_err(&pdev->dev, "failed to get match data\n"); @@ -1003,7 +722,6 @@ static int meson_dw_hdmi_bind(struct device *dev, stru= ct device *master, meson_dw_hdmi->dev =3D dev; meson_dw_hdmi->data =3D match; dw_plat_data =3D &meson_dw_hdmi->dw_plat_data; - encoder =3D &meson_dw_hdmi->encoder; =20 meson_dw_hdmi->hdmi_supply =3D devm_regulator_get_optional(dev, "hdmi"); if (IS_ERR(meson_dw_hdmi->hdmi_supply)) { @@ -1074,28 +792,11 @@ static int meson_dw_hdmi_bind(struct device *dev, st= ruct device *master, return ret; } =20 - /* Encoder */ - - ret =3D drm_encoder_init(drm, encoder, &meson_venc_hdmi_encoder_funcs, - DRM_MODE_ENCODER_TMDS, "meson_hdmi"); - if (ret) { - dev_err(priv->dev, "Failed to init HDMI encoder\n"); - return ret; - } - - meson_dw_hdmi->bridge.funcs =3D &meson_venc_hdmi_encoder_bridge_funcs; - drm_bridge_attach(encoder, &meson_dw_hdmi->bridge, NULL, 0); - - encoder->possible_crtcs =3D BIT(0); - meson_dw_hdmi_init(meson_dw_hdmi); =20 - DRM_DEBUG_DRIVER("encoder initialized\n"); - /* Bridge / Connector */ =20 dw_plat_data->priv_data =3D meson_dw_hdmi; - dw_plat_data->mode_valid =3D dw_hdmi_mode_valid; dw_plat_data->phy_ops =3D &meson_dw_hdmi_phy_ops; dw_plat_data->phy_name =3D "meson_dw_hdmi_phy"; dw_plat_data->phy_data =3D meson_dw_hdmi; @@ -1110,15 +811,11 @@ static int meson_dw_hdmi_bind(struct device *dev, st= ruct device *master, =20 platform_set_drvdata(pdev, meson_dw_hdmi); =20 - meson_dw_hdmi->hdmi =3D dw_hdmi_probe(pdev, - &meson_dw_hdmi->dw_plat_data); + meson_dw_hdmi->hdmi =3D dw_hdmi_probe(pdev, &meson_dw_hdmi->dw_plat_data); if (IS_ERR(meson_dw_hdmi->hdmi)) return PTR_ERR(meson_dw_hdmi->hdmi); =20 - next_bridge =3D of_drm_find_bridge(pdev->dev.of_node); - if (next_bridge) - drm_bridge_attach(encoder, next_bridge, - &meson_dw_hdmi->bridge, 0); + meson_dw_hdmi->bridge =3D of_drm_find_bridge(pdev->dev.of_node); =20 DRM_DEBUG_DRIVER("HDMI controller initialized\n"); =20 diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/m= eson/meson_encoder_hdmi.c new file mode 100644 index 000000000000..db332fa4cd54 --- /dev/null +++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c @@ -0,0 +1,370 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2016 BayLibre, SAS + * Author: Neil Armstrong + * Copyright (C) 2015 Amlogic, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "meson_drv.h" +#include "meson_registers.h" +#include "meson_vclk.h" +#include "meson_venc.h" +#include "meson_encoder_hdmi.h" + +struct meson_encoder_hdmi { + struct drm_encoder encoder; + struct drm_bridge bridge; + struct drm_bridge *next_bridge; + struct meson_drm *priv; + unsigned long output_bus_fmt; +}; + +#define bridge_to_meson_encoder_hdmi(x) \ + container_of(x, struct meson_encoder_hdmi, bridge) + +static int meson_encoder_hdmi_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct meson_encoder_hdmi *encoder_hdmi =3D bridge_to_meson_encoder_hdmi(= bridge); + + return drm_bridge_attach(bridge->encoder, encoder_hdmi->next_bridge, + &encoder_hdmi->bridge, flags); +} + +static void meson_encoder_hdmi_set_vclk(struct meson_encoder_hdmi *encoder= _hdmi, + const struct drm_display_mode *mode) +{ + struct meson_drm *priv =3D encoder_hdmi->priv; + int vic =3D drm_match_cea_mode(mode); + unsigned int phy_freq; + unsigned int vclk_freq; + unsigned int venc_freq; + unsigned int hdmi_freq; + + vclk_freq =3D mode->clock; + + /* For 420, pixel clock is half unlike venc clock */ + if (encoder_hdmi->output_bus_fmt =3D=3D MEDIA_BUS_FMT_UYYVYY8_0_5X24) + vclk_freq /=3D 2; + + /* TMDS clock is pixel_clock * 10 */ + phy_freq =3D vclk_freq * 10; + + if (!vic) { + meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, phy_freq, + vclk_freq, vclk_freq, vclk_freq, false); + return; + } + + /* 480i/576i needs global pixel doubling */ + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + vclk_freq *=3D 2; + + venc_freq =3D vclk_freq; + hdmi_freq =3D vclk_freq; + + /* VENC double pixels for 1080i, 720p and YUV420 modes */ + if (meson_venc_hdmi_venc_repeat(vic) || + encoder_hdmi->output_bus_fmt =3D=3D MEDIA_BUS_FMT_UYYVYY8_0_5X24) + venc_freq *=3D 2; + + vclk_freq =3D max(venc_freq, hdmi_freq); + + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + venc_freq /=3D 2; + + dev_dbg(priv->dev, "vclk:%d phy=3D%d venc=3D%d hdmi=3D%d enci=3D%d\n", + phy_freq, vclk_freq, venc_freq, hdmi_freq, + priv->venc.hdmi_use_enci); + + meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, phy_freq, vclk_freq, + venc_freq, hdmi_freq, priv->venc.hdmi_use_enci); +} + +static enum drm_mode_status meson_encoder_hdmi_mode_valid(struct drm_bridg= e *bridge, + const struct drm_display_info *display_info, + const struct drm_display_mode *mode) +{ + struct meson_encoder_hdmi *encoder_hdmi =3D bridge_to_meson_encoder_hdmi(= bridge); + struct meson_drm *priv =3D encoder_hdmi->priv; + bool is_hdmi2_sink =3D display_info->hdmi.scdc.supported; + unsigned int phy_freq; + unsigned int vclk_freq; + unsigned int venc_freq; + unsigned int hdmi_freq; + int vic =3D drm_match_cea_mode(mode); + enum drm_mode_status status; + + dev_dbg(priv->dev, "Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); + + /* If sink does not support 540MHz, reject the non-420 HDMI2 modes */ + if (display_info->max_tmds_clock && + mode->clock > display_info->max_tmds_clock && + !drm_mode_is_420_only(display_info, mode) && + !drm_mode_is_420_also(display_info, mode)) + return MODE_BAD; + + /* Check against non-VIC supported modes */ + if (!vic) { + status =3D meson_venc_hdmi_supported_mode(mode); + if (status !=3D MODE_OK) + return status; + + return meson_vclk_dmt_supported_freq(priv, mode->clock); + /* Check against supported VIC modes */ + } else if (!meson_venc_hdmi_supported_vic(vic)) + return MODE_BAD; + + vclk_freq =3D mode->clock; + + /* For 420, pixel clock is half unlike venc clock */ + if (drm_mode_is_420_only(display_info, mode) || + (!is_hdmi2_sink && + drm_mode_is_420_also(display_info, mode))) + vclk_freq /=3D 2; + + /* TMDS clock is pixel_clock * 10 */ + phy_freq =3D vclk_freq * 10; + + /* 480i/576i needs global pixel doubling */ + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + vclk_freq *=3D 2; + + venc_freq =3D vclk_freq; + hdmi_freq =3D vclk_freq; + + /* VENC double pixels for 1080i, 720p and YUV420 modes */ + if (meson_venc_hdmi_venc_repeat(vic) || + drm_mode_is_420_only(display_info, mode) || + (!is_hdmi2_sink && + drm_mode_is_420_also(display_info, mode))) + venc_freq *=3D 2; + + vclk_freq =3D max(venc_freq, hdmi_freq); + + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + venc_freq /=3D 2; + + dev_dbg(priv->dev, "%s: vclk:%d phy=3D%d venc=3D%d hdmi=3D%d\n", + __func__, phy_freq, vclk_freq, venc_freq, hdmi_freq); + + return meson_vclk_vic_supported_freq(priv, phy_freq, vclk_freq); +} + +static void meson_encoder_hdmi_atomic_enable(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state) +{ + struct meson_encoder_hdmi *encoder_hdmi =3D bridge_to_meson_encoder_hdmi(= bridge); + struct drm_atomic_state *state =3D bridge_state->base.state; + unsigned int ycrcb_map =3D VPU_HDMI_OUTPUT_CBYCR; + struct meson_drm *priv =3D encoder_hdmi->priv; + struct drm_connector_state *conn_state; + const struct drm_display_mode *mode; + struct drm_crtc_state *crtc_state; + struct drm_connector *connector; + bool yuv420_mode =3D false; + int vic; + + connector =3D drm_atomic_get_new_connector_for_encoder(state, bridge->enc= oder); + if (WARN_ON(!connector)) + return; + + conn_state =3D drm_atomic_get_new_connector_state(state, connector); + if (WARN_ON(!conn_state)) + return; + + crtc_state =3D drm_atomic_get_new_crtc_state(state, conn_state->crtc); + if (WARN_ON(!crtc_state)) + return; + + mode =3D &crtc_state->adjusted_mode; + + vic =3D drm_match_cea_mode(mode); + + dev_dbg(priv->dev, "\"%s\" vic %d\n", mode->name, vic); + + if (encoder_hdmi->output_bus_fmt =3D=3D MEDIA_BUS_FMT_UYYVYY8_0_5X24) { + ycrcb_map =3D VPU_HDMI_OUTPUT_CRYCB; + yuv420_mode =3D true; + } + + /* VENC + VENC-DVI Mode setup */ + meson_venc_hdmi_mode_set(priv, vic, ycrcb_map, yuv420_mode, mode); + + /* VCLK Set clock */ + meson_encoder_hdmi_set_vclk(encoder_hdmi, mode); + + if (encoder_hdmi->output_bus_fmt =3D=3D MEDIA_BUS_FMT_UYYVYY8_0_5X24) + /* Setup YUV420 to HDMI-TX, no 10bit diphering */ + writel_relaxed(2 | (2 << 2), + priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); + else + /* Setup YUV444 to HDMI-TX, no 10bit diphering */ + writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); + + dev_dbg(priv->dev, "%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP"); + + if (priv->venc.hdmi_use_enci) + writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN)); + else + writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN)); +} + +static void meson_encoder_hdmi_atomic_disable(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state) +{ + struct meson_encoder_hdmi *encoder_hdmi =3D bridge_to_meson_encoder_hdmi(= bridge); + struct meson_drm *priv =3D encoder_hdmi->priv; + + writel_bits_relaxed(0x3, 0, + priv->io_base + _REG(VPU_HDMI_SETTING)); + + writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN)); + writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN)); +} + +static const u32 meson_encoder_hdmi_out_bus_fmts[] =3D { + MEDIA_BUS_FMT_YUV8_1X24, + MEDIA_BUS_FMT_UYYVYY8_0_5X24, +}; + +static u32 * +meson_encoder_hdmi_get_inp_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts) +{ + u32 *input_fmts =3D NULL; + int i; + + *num_input_fmts =3D 0; + + for (i =3D 0 ; i < ARRAY_SIZE(meson_encoder_hdmi_out_bus_fmts) ; ++i) { + if (output_fmt =3D=3D meson_encoder_hdmi_out_bus_fmts[i]) { + *num_input_fmts =3D 1; + input_fmts =3D kcalloc(*num_input_fmts, + sizeof(*input_fmts), + GFP_KERNEL); + if (!input_fmts) + return NULL; + + input_fmts[0] =3D output_fmt; + + break; + } + } + + return input_fmts; +} + +static int meson_encoder_hdmi_atomic_check(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct meson_encoder_hdmi *encoder_hdmi =3D bridge_to_meson_encoder_hdmi(= bridge); + struct drm_connector_state *old_conn_state =3D + drm_atomic_get_old_connector_state(conn_state->state, conn_state->connec= tor); + struct meson_drm *priv =3D encoder_hdmi->priv; + + encoder_hdmi->output_bus_fmt =3D bridge_state->output_bus_cfg.format; + + dev_dbg(priv->dev, "output_bus_fmt %lx\n", encoder_hdmi->output_bus_fmt); + + if (!drm_connector_atomic_hdr_metadata_equal(old_conn_state, conn_state)) + crtc_state->mode_changed =3D true; + + return 0; +} + +static const struct drm_bridge_funcs meson_encoder_hdmi_bridge_funcs =3D { + .attach =3D meson_encoder_hdmi_attach, + .mode_valid =3D meson_encoder_hdmi_mode_valid, + .atomic_enable =3D meson_encoder_hdmi_atomic_enable, + .atomic_disable =3D meson_encoder_hdmi_atomic_disable, + .atomic_get_input_bus_fmts =3D meson_encoder_hdmi_get_inp_bus_fmts, + .atomic_check =3D meson_encoder_hdmi_atomic_check, + .atomic_duplicate_state =3D drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state =3D drm_atomic_helper_bridge_destroy_state, + .atomic_reset =3D drm_atomic_helper_bridge_reset, +}; + +int meson_encoder_hdmi_init(struct meson_drm *priv) +{ + struct meson_encoder_hdmi *meson_encoder_hdmi; + struct device_node *remote; + int ret; + + meson_encoder_hdmi =3D devm_kzalloc(priv->dev, sizeof(*meson_encoder_hdmi= ), GFP_KERNEL); + if (!meson_encoder_hdmi) + return -ENOMEM; + + /* HDMI Transceiver Bridge */ + remote =3D of_graph_get_remote_node(priv->dev->of_node, 1, 0); + if (!remote) { + dev_err(priv->dev, "HDMI transceiver device is disabled"); + return 0; + } + + meson_encoder_hdmi->next_bridge =3D of_drm_find_bridge(remote); + if (!meson_encoder_hdmi->next_bridge) { + dev_err(priv->dev, "Failed to find HDMI transceiver bridge\n"); + return -EPROBE_DEFER; + } + + /* HDMI Encoder Bridge */ + meson_encoder_hdmi->bridge.funcs =3D &meson_encoder_hdmi_bridge_funcs; + meson_encoder_hdmi->bridge.of_node =3D priv->dev->of_node; + meson_encoder_hdmi->bridge.type =3D DRM_MODE_CONNECTOR_HDMIA; + + drm_bridge_add(&meson_encoder_hdmi->bridge); + + meson_encoder_hdmi->priv =3D priv; + + /* Encoder */ + ret =3D drm_simple_encoder_init(priv->drm, &meson_encoder_hdmi->encoder, + DRM_MODE_ENCODER_TMDS); + if (ret) { + dev_err(priv->dev, "Failed to init HDMI encoder: %d\n", ret); + return ret; + } + + meson_encoder_hdmi->encoder.possible_crtcs =3D BIT(0); + + /* Attach HDMI Encoder Bridge to Encoder */ + ret =3D drm_bridge_attach(&meson_encoder_hdmi->encoder, &meson_encoder_hd= mi->bridge, NULL, 0); + if (ret) { + dev_err(priv->dev, "Failed to attach bridge: %d\n", ret); + return ret; + } + + /* + * We should have now in place: + * encoder->[hdmi encoder bridge]->[dw-hdmi bridge]->[dw-hdmi connector] + */ + + dev_dbg(priv->dev, "HDMI encoder initialized\n"); + + return 0; +} diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.h b/drivers/gpu/drm/m= eson/meson_encoder_hdmi.h new file mode 100644 index 000000000000..ed19494f0956 --- /dev/null +++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021 BayLibre, SAS + * Author: Neil Armstrong + */ + +#ifndef __MESON_ENCODER_HDMI_H +#define __MESON_ENCODER_HDMI_H + +int meson_encoder_hdmi_init(struct meson_drm *priv); + +#endif /* __MESON_ENCODER_HDMI_H */ diff --git a/drivers/gpu/drm/meson/meson_osd_afbcd.c b/drivers/gpu/drm/meso= n/meson_osd_afbcd.c index ffc6b584dbf8..0cdbe899402f 100644 --- a/drivers/gpu/drm/meson/meson_osd_afbcd.c +++ b/drivers/gpu/drm/meson/meson_osd_afbcd.c @@ -79,11 +79,6 @@ static bool meson_gxm_afbcd_supported_fmt(u64 modifier, = uint32_t format) return meson_gxm_afbcd_pixel_fmt(modifier, format) >=3D 0; } =20 -static int meson_gxm_afbcd_init(struct meson_drm *priv) -{ - return 0; -} - static int meson_gxm_afbcd_reset(struct meson_drm *priv) { writel_relaxed(VIU_SW_RESET_OSD1_AFBCD, @@ -93,6 +88,16 @@ static int meson_gxm_afbcd_reset(struct meson_drm *priv) return 0; } =20 +static int meson_gxm_afbcd_init(struct meson_drm *priv) +{ + return 0; +} + +static void meson_gxm_afbcd_exit(struct meson_drm *priv) +{ + meson_gxm_afbcd_reset(priv); +} + static int meson_gxm_afbcd_enable(struct meson_drm *priv) { writel_relaxed(FIELD_PREP(OSD1_AFBCD_ID_FIFO_THRD, 0x40) | @@ -172,6 +177,7 @@ static int meson_gxm_afbcd_setup(struct meson_drm *priv) =20 struct meson_afbcd_ops meson_afbcd_gxm_ops =3D { .init =3D meson_gxm_afbcd_init, + .exit =3D meson_gxm_afbcd_exit, .reset =3D meson_gxm_afbcd_reset, .enable =3D meson_gxm_afbcd_enable, .disable =3D meson_gxm_afbcd_disable, @@ -269,6 +275,18 @@ static bool meson_g12a_afbcd_supported_fmt(u64 modifie= r, uint32_t format) return meson_g12a_afbcd_pixel_fmt(modifier, format) >=3D 0; } =20 +static int meson_g12a_afbcd_reset(struct meson_drm *priv) +{ + meson_rdma_reset(priv); + + meson_rdma_writel_sync(priv, VIU_SW_RESET_G12A_AFBC_ARB | + VIU_SW_RESET_G12A_OSD1_AFBCD, + VIU_SW_RESET); + meson_rdma_writel_sync(priv, 0, VIU_SW_RESET); + + return 0; +} + static int meson_g12a_afbcd_init(struct meson_drm *priv) { int ret; @@ -286,16 +304,10 @@ static int meson_g12a_afbcd_init(struct meson_drm *pr= iv) return 0; } =20 -static int meson_g12a_afbcd_reset(struct meson_drm *priv) +static void meson_g12a_afbcd_exit(struct meson_drm *priv) { - meson_rdma_reset(priv); - - meson_rdma_writel_sync(priv, VIU_SW_RESET_G12A_AFBC_ARB | - VIU_SW_RESET_G12A_OSD1_AFBCD, - VIU_SW_RESET); - meson_rdma_writel_sync(priv, 0, VIU_SW_RESET); - - return 0; + meson_g12a_afbcd_reset(priv); + meson_rdma_free(priv); } =20 static int meson_g12a_afbcd_enable(struct meson_drm *priv) @@ -380,6 +392,7 @@ static int meson_g12a_afbcd_setup(struct meson_drm *pri= v) =20 struct meson_afbcd_ops meson_afbcd_g12a_ops =3D { .init =3D meson_g12a_afbcd_init, + .exit =3D meson_g12a_afbcd_exit, .reset =3D meson_g12a_afbcd_reset, .enable =3D meson_g12a_afbcd_enable, .disable =3D meson_g12a_afbcd_disable, diff --git a/drivers/gpu/drm/meson/meson_osd_afbcd.h b/drivers/gpu/drm/meso= n/meson_osd_afbcd.h index 5e5523304f42..e77ddeb6416f 100644 --- a/drivers/gpu/drm/meson/meson_osd_afbcd.h +++ b/drivers/gpu/drm/meson/meson_osd_afbcd.h @@ -14,6 +14,7 @@ =20 struct meson_afbcd_ops { int (*init)(struct meson_drm *priv); + void (*exit)(struct meson_drm *priv); int (*reset)(struct meson_drm *priv); int (*enable)(struct meson_drm *priv); int (*disable)(struct meson_drm *priv); diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag2= 00/mgag200_mode.c index fd98e8bbc550..2c7271f545dc 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -529,7 +529,10 @@ static void mgag200_set_format_regs(struct mga_device = *mdev, WREG_GFX(3, 0x00); WREG_GFX(4, 0x00); WREG_GFX(5, 0x40); - WREG_GFX(6, 0x05); + /* GCTL6 should be 0x05, but we configure memmapsl to 0xb8000 (text mode), + * so that it doesn't hang when running kexec/kdump on G200_SE rev42. + */ + WREG_GFX(6, 0x0d); WREG_GFX(7, 0x0f); WREG_GFX(8, 0x0f); =20 diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/ad= reno/a6xx_gpu.c index a305ff7e8c6f..f880a59a40fc 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -658,19 +658,23 @@ static void a6xx_set_cp_protect(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu =3D to_adreno_gpu(gpu); const u32 *regs =3D a6xx_protect; - unsigned i, count =3D ARRAY_SIZE(a6xx_protect), count_max =3D 32; - - BUILD_BUG_ON(ARRAY_SIZE(a6xx_protect) > 32); - BUILD_BUG_ON(ARRAY_SIZE(a650_protect) > 48); + unsigned i, count, count_max; =20 if (adreno_is_a650(adreno_gpu)) { regs =3D a650_protect; count =3D ARRAY_SIZE(a650_protect); count_max =3D 48; + BUILD_BUG_ON(ARRAY_SIZE(a650_protect) > 48); } else if (adreno_is_a660_family(adreno_gpu)) { regs =3D a660_protect; count =3D ARRAY_SIZE(a660_protect); count_max =3D 48; + BUILD_BUG_ON(ARRAY_SIZE(a660_protect) > 48); + } else { + regs =3D a6xx_protect; + count =3D ARRAY_SIZE(a6xx_protect); + count_max =3D 32; + BUILD_BUG_ON(ARRAY_SIZE(a6xx_protect) > 32); } =20 /* diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/= msm/disp/dpu1/dpu_encoder.c index e7ee4cfb8461..ad27a01c22af 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -1102,7 +1102,7 @@ static void _dpu_encoder_virt_enable_helper(struct dr= m_encoder *drm_enc) } =20 =20 - if (dpu_enc->disp_info.intf_type =3D=3D DRM_MODE_CONNECTOR_DisplayPort && + if (dpu_enc->disp_info.intf_type =3D=3D DRM_MODE_ENCODER_TMDS && dpu_enc->cur_master->hw_mdptop && dpu_enc->cur_master->hw_mdptop->ops.intf_audio_select) dpu_enc->cur_master->hw_mdptop->ops.intf_audio_select( diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/d= isp/dpu1/dpu_rm.c index f9c83d6e427a..24fbaf562d41 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -35,6 +35,14 @@ int dpu_rm_destroy(struct dpu_rm *rm) { int i; =20 + for (i =3D 0; i < ARRAY_SIZE(rm->dspp_blks); i++) { + struct dpu_hw_dspp *hw; + + if (rm->dspp_blks[i]) { + hw =3D to_dpu_hw_dspp(rm->dspp_blks[i]); + dpu_hw_dspp_destroy(hw); + } + } for (i =3D 0; i < ARRAY_SIZE(rm->pingpong_blks); i++) { struct dpu_hw_pingpong *hw; =20 diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_c= trl.c index 62e75dc8afc6..4af281d97493 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -1744,6 +1744,9 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl) /* end with failure */ break; /* lane =3D=3D 1 already */ } + + /* stop link training before start re training */ + dp_ctrl_clear_training_pattern(ctrl); } } =20 diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/d= p_display.c index aba8aa47ed76..98a546a65091 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -1455,6 +1455,7 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, st= ruct drm_device *dev, struct drm_encoder *encoder) { struct msm_drm_private *priv; + struct dp_display_private *dp_priv; int ret; =20 if (WARN_ON(!encoder) || WARN_ON(!dp_display) || WARN_ON(!dev)) @@ -1463,6 +1464,8 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, st= ruct drm_device *dev, priv =3D dev->dev_private; dp_display->drm_dev =3D dev; =20 + dp_priv =3D container_of(dp_display, struct dp_display_private, dp_displa= y); + ret =3D dp_display_request_irq(dp_display); if (ret) { DRM_ERROR("request_irq failed, ret=3D%d\n", ret); @@ -1480,6 +1483,8 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, st= ruct drm_device *dev, return ret; } =20 + dp_priv->panel->connector =3D dp_display->connector; + priv->connectors[priv->num_connectors++] =3D dp_display->connector; return 0; } diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_= panel.c index 71db10c0f262..f1418722c549 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.c +++ b/drivers/gpu/drm/msm/dp/dp_panel.c @@ -212,6 +212,11 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel, if (drm_add_modes_noedid(connector, 640, 480)) drm_set_preferred_mode(connector, 640, 480); mutex_unlock(&connector->dev->mode_config.mutex); + } else { + /* always add fail-safe mode as backup mode */ + mutex_lock(&connector->dev->mode_config.mutex); + drm_add_modes_noedid(connector, 640, 480); + mutex_unlock(&connector->dev->mode_config.mutex); } =20 if (panel->aux_cfg_update_done) { diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c b/drivers/gpu/drm/m= sm/dsi/phy/dsi_phy_10nm.c index d8128f50b0dd..0b782cc18b3f 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c @@ -562,7 +562,9 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_1= 0nm, struct clk_hw **prov char clk_name[32], parent[32], vco_name[32]; char parent2[32], parent3[32], parent4[32]; struct clk_init_data vco_init =3D { - .parent_names =3D (const char *[]){ "xo" }, + .parent_data =3D &(const struct clk_parent_data) { + .fw_name =3D "ref", + }, .num_parents =3D 1, .name =3D vco_name, .flags =3D CLK_IGNORE_UNUSED, diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c b/drivers/gpu/drm/m= sm/dsi/phy/dsi_phy_14nm.c index 7414966f198e..75557ac99adf 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c @@ -802,7 +802,9 @@ static int pll_14nm_register(struct dsi_pll_14nm *pll_1= 4nm, struct clk_hw **prov { char clk_name[32], parent[32], vco_name[32]; struct clk_init_data vco_init =3D { - .parent_names =3D (const char *[]){ "xo" }, + .parent_data =3D &(const struct clk_parent_data) { + .fw_name =3D "ref", + }, .num_parents =3D 1, .name =3D vco_name, .flags =3D CLK_IGNORE_UNUSED, diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c b/drivers/gpu/drm/m= sm/dsi/phy/dsi_phy_28nm.c index 2da673a2add6..48eab80b548e 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c @@ -521,7 +521,9 @@ static int pll_28nm_register(struct dsi_pll_28nm *pll_2= 8nm, struct clk_hw **prov { char clk_name[32], parent1[32], parent2[32], vco_name[32]; struct clk_init_data vco_init =3D { - .parent_names =3D (const char *[]){ "xo" }, + .parent_data =3D &(const struct clk_parent_data) { + .fw_name =3D "ref", .name =3D "xo", + }, .num_parents =3D 1, .name =3D vco_name, .flags =3D CLK_IGNORE_UNUSED, diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c b/drivers/gpu/= drm/msm/dsi/phy/dsi_phy_28nm_8960.c index 71ed4aa0dc67..fc56cdcc9ad6 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c @@ -385,7 +385,9 @@ static int pll_28nm_register(struct dsi_pll_28nm *pll_2= 8nm, struct clk_hw **prov { char *clk_name, *parent_name, *vco_name; struct clk_init_data vco_init =3D { - .parent_names =3D (const char *[]){ "pxo" }, + .parent_data =3D &(const struct clk_parent_data) { + .fw_name =3D "ref", + }, .num_parents =3D 1, .flags =3D CLK_IGNORE_UNUSED, .ops =3D &clk_ops_dsi_pll_28nm_vco, diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c b/drivers/gpu/drm/ms= m/dsi/phy/dsi_phy_7nm.c index 079613d2aaa9..6e506feb111f 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c @@ -588,7 +588,9 @@ static int pll_7nm_register(struct dsi_pll_7nm *pll_7nm= , struct clk_hw **provide char clk_name[32], parent[32], vco_name[32]; char parent2[32], parent3[32], parent4[32]; struct clk_init_data vco_init =3D { - .parent_names =3D (const char *[]){ "bi_tcxo" }, + .parent_data =3D &(const struct clk_parent_data) { + .fw_name =3D "ref", + }, .num_parents =3D 1, .name =3D vco_name, .flags =3D CLK_IGNORE_UNUSED, @@ -862,20 +864,26 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy, /* Alter PHY configurations if data rate less than 1.5GHZ*/ less_than_1500_mhz =3D (clk_req->bitclk_rate <=3D 1500000000); =20 - /* For C-PHY, no low power settings for lower clk rate */ - if (phy->cphy_mode) - less_than_1500_mhz =3D false; - if (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1) { vreg_ctrl_0 =3D less_than_1500_mhz ? 0x53 : 0x52; - glbl_rescode_top_ctrl =3D less_than_1500_mhz ? 0x3d : 0x00; - glbl_rescode_bot_ctrl =3D less_than_1500_mhz ? 0x39 : 0x3c; + if (phy->cphy_mode) { + glbl_rescode_top_ctrl =3D 0x00; + glbl_rescode_bot_ctrl =3D 0x3c; + } else { + glbl_rescode_top_ctrl =3D less_than_1500_mhz ? 0x3d : 0x00; + glbl_rescode_bot_ctrl =3D less_than_1500_mhz ? 0x39 : 0x3c; + } glbl_str_swi_cal_sel_ctrl =3D 0x00; glbl_hstx_str_ctrl_0 =3D 0x88; } else { vreg_ctrl_0 =3D less_than_1500_mhz ? 0x5B : 0x59; - glbl_str_swi_cal_sel_ctrl =3D less_than_1500_mhz ? 0x03 : 0x00; - glbl_hstx_str_ctrl_0 =3D less_than_1500_mhz ? 0x66 : 0x88; + if (phy->cphy_mode) { + glbl_str_swi_cal_sel_ctrl =3D 0x03; + glbl_hstx_str_ctrl_0 =3D 0x66; + } else { + glbl_str_swi_cal_sel_ctrl =3D less_than_1500_mhz ? 0x03 : 0x00; + glbl_hstx_str_ctrl_0 =3D less_than_1500_mhz ? 0x66 : 0x88; + } glbl_rescode_top_ctrl =3D 0x03; glbl_rescode_bot_ctrl =3D 0x3c; } diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/= nouveau/nouveau_backlight.c index 1cbd71abc80a..12965a832f94 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -101,7 +101,6 @@ nv40_backlight_init(struct nouveau_encoder *encoder, if (!(nvif_rd32(device, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK)) return -ENODEV; =20 - props->type =3D BACKLIGHT_RAW; props->max_brightness =3D 31; *ops =3D &nv40_bl_ops; return 0; @@ -294,7 +293,8 @@ nv50_backlight_init(struct nouveau_backlight *bl, struct nouveau_drm *drm =3D nouveau_drm(nv_encoder->base.base.dev); struct nvif_object *device =3D &drm->client.device.object; =20 - if (!nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(ffs(nv_encoder->dcb->or) - = 1))) + if (!nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(ffs(nv_encoder->dcb->or) - = 1)) || + nv_conn->base.status !=3D connector_status_connected) return -ENODEV; =20 if (nv_conn->type =3D=3D DCB_CONNECTOR_eDP) { @@ -339,7 +339,6 @@ nv50_backlight_init(struct nouveau_backlight *bl, else *ops =3D &nva3_bl_ops; =20 - props->type =3D BACKLIGHT_RAW; props->max_brightness =3D 100; =20 return 0; @@ -407,6 +406,7 @@ nouveau_backlight_init(struct drm_connector *connector) goto fail_alloc; } =20 + props.type =3D BACKLIGHT_RAW; bl->dev =3D backlight_device_register(backlight_name, connector->kdev, nv_encoder, ops, &props); if (IS_ERR(bl->dev)) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/hsfw.c b/drivers/gpu/d= rm/nouveau/nvkm/subdev/acr/hsfw.c index 667fa016496e..a6ea89a5d51a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/hsfw.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/hsfw.c @@ -142,11 +142,12 @@ nvkm_acr_hsfw_load_bl(struct nvkm_acr *acr, const cha= r *name, int ver, =20 hsfw->imem_size =3D desc->code_size; hsfw->imem_tag =3D desc->start_tag; - hsfw->imem =3D kmalloc(desc->code_size, GFP_KERNEL); - memcpy(hsfw->imem, data + desc->code_off, desc->code_size); - + hsfw->imem =3D kmemdup(data + desc->code_off, desc->code_size, GFP_KERNEL= ); nvkm_firmware_put(fw); - return 0; + if (!hsfw->imem) + return -ENOMEM; + else + return 0; } =20 int diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panf= rost/panfrost_gpu.c index bbe628b306ee..f8355de6e335 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -360,8 +360,11 @@ int panfrost_gpu_init(struct panfrost_device *pfdev) =20 panfrost_gpu_init_features(pfdev); =20 - dma_set_mask_and_coherent(pfdev->dev, + err =3D dma_set_mask_and_coherent(pfdev->dev, DMA_BIT_MASK(FIELD_GET(0xff00, pfdev->features.mmu_features))); + if (err) + return err; + dma_set_max_seg_size(pfdev->dev, UINT_MAX); =20 irq =3D platform_get_irq_byname(to_platform_device(pfdev->dev), "gpu"); diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/r= adeon/radeon_connectors.c index 607ad5620bd9..1546abcadacf 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -204,7 +204,7 @@ int radeon_get_monitor_bpc(struct drm_connector *connec= tor) =20 /* Check if bpc is within clock limit. Try to degrade gracefully otherw= ise */ if ((bpc =3D=3D 12) && (mode_clock * 3/2 > max_tmds_clock)) { - if ((connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30)= && + if ((connector->display_info.edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI= _DC_30) && (mode_clock * 5/4 <=3D max_tmds_clock)) bpc =3D 10; else diff --git a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c b/drivers/g= pu/drm/selftests/test-drm_dp_mst_helper.c index 6b4759ed6bfd..c491429f1a02 100644 --- a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c +++ b/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c @@ -131,8 +131,10 @@ sideband_msg_req_encode_decode(struct drm_dp_sideband_= msg_req_body *in) return false; =20 txmsg =3D kzalloc(sizeof(*txmsg), GFP_KERNEL); - if (!txmsg) + if (!txmsg) { + kfree(out); return false; + } =20 drm_dp_encode_sideband_req(in, txmsg); ret =3D drm_dp_decode_sideband_req(txmsg, out); diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index f46d377f0c30..de1333dc0d86 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1538,8 +1538,10 @@ static int tegra_dsi_ganged_probe(struct tegra_dsi *= dsi) dsi->slave =3D platform_get_drvdata(gangster); of_node_put(np); =20 - if (!dsi->slave) + if (!dsi->slave) { + put_device(&gangster->dev); return -EPROBE_DEFER; + } =20 dsi->slave->master =3D dsi; } diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simple= drm.c index 5a6e89825bc2..3e3f9ba1e885 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -779,6 +779,9 @@ static int simpledrm_device_init_modeset(struct simpled= rm_device *sdev) if (ret) return ret; drm_connector_helper_add(connector, &simpledrm_connector_helper_funcs); + drm_connector_set_panel_orientation_with_quirk(connector, + DRM_MODE_PANEL_ORIENTATION_UNKNOWN, + mode->hdisplay, mode->vdisplay); =20 formats =3D simpledrm_device_formats(sdev, &nformats); =20 diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index bd46396a1ae0..1afcd54fbbd5 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -219,6 +219,7 @@ static int v3d_platform_drm_probe(struct platform_devic= e *pdev) int ret; u32 mmu_debug; u32 ident1; + u64 mask; =20 v3d =3D devm_drm_dev_alloc(dev, &v3d_drm_driver, struct v3d_dev, drm); if (IS_ERR(v3d)) @@ -237,8 +238,11 @@ static int v3d_platform_drm_probe(struct platform_devi= ce *pdev) return ret; =20 mmu_debug =3D V3D_READ(V3D_MMU_DEBUG_INFO); - dma_set_mask_and_coherent(dev, - DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH))); + mask =3D DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH)); + ret =3D dma_set_mask_and_coherent(dev, mask); + if (ret) + return ret; + v3d->va_width =3D 30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_VA_WIDTH); =20 ident1 =3D V3D_READ(V3D_HUB_IDENT1); diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 3872e4cd2698..fc9f54282f7d 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -526,6 +526,7 @@ static int host1x_remove(struct platform_device *pdev) host1x_syncpt_deinit(host); reset_control_assert(host->rst); clk_disable_unprepare(host->clk); + host1x_channel_list_free(&host->channel_list); host1x_iommu_exit(host); =20 return 0; diff --git a/drivers/greybus/svc.c b/drivers/greybus/svc.c index ce7740ef449b..51d0875a3480 100644 --- a/drivers/greybus/svc.c +++ b/drivers/greybus/svc.c @@ -866,8 +866,14 @@ static int gb_svc_hello(struct gb_operation *op) =20 gb_svc_debugfs_init(svc); =20 - return gb_svc_queue_deferred_request(op); + ret =3D gb_svc_queue_deferred_request(op); + if (ret) + goto err_remove_debugfs; + + return 0; =20 +err_remove_debugfs: + gb_svc_debugfs_exit(svc); err_unregister_device: gb_svc_watchdog_destroy(svc); device_del(&svc->dev); diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 7106b921b53c..c358778e070b 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -1068,6 +1068,7 @@ static void logi_hidpp_recv_queue_notif(struct hid_de= vice *hdev, workitem.reports_supported |=3D STD_KEYBOARD; break; case 0x0f: + case 0x11: device_type =3D "eQUAD Lightspeed 1.2"; logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem); workitem.reports_supported |=3D STD_KEYBOARD; diff --git a/drivers/hid/hid-thrustmaster.c b/drivers/hid/hid-thrustmaster.c index 9da4240530dd..c3e6d69fdfbd 100644 --- a/drivers/hid/hid-thrustmaster.c +++ b/drivers/hid/hid-thrustmaster.c @@ -64,7 +64,9 @@ struct tm_wheel_info { */ static const struct tm_wheel_info tm_wheels_infos[] =3D { {0x0306, 0x0006, "Thrustmaster T150RS"}, + {0x0200, 0x0005, "Thrustmaster T300RS (Missing Attachment)"}, {0x0206, 0x0005, "Thrustmaster T300RS"}, + {0x0209, 0x0005, "Thrustmaster T300RS (Open Wheel Attachment)"}, {0x0204, 0x0005, "Thrustmaster T300 Ferrari Alcantara Edition"}, {0x0002, 0x0002, "Thrustmaster T500RS"} //{0x0407, 0x0001, "Thrustmaster TMX"} diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-h= id-core.c index 4804d71e5293..65c1f20ec420 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -615,6 +615,17 @@ static int i2c_hid_get_raw_report(struct hid_device *h= id, if (report_type =3D=3D HID_OUTPUT_REPORT) return -EINVAL; =20 + /* + * In case of unnumbered reports the response from the device will + * not have the report ID that the upper layers expect, so we need + * to stash it the buffer ourselves and adjust the data size. + */ + if (!report_number) { + buf[0] =3D 0; + buf++; + count--; + } + /* +2 bytes to include the size of the reply in the query buffer */ ask_count =3D min(count + 2, (size_t)ihid->bufsize); =20 @@ -636,6 +647,9 @@ static int i2c_hid_get_raw_report(struct hid_device *hi= d, count =3D min(count, ret_count - 2); memcpy(buf, ihid->rawbuf + 2, count); =20 + if (!report_number) + count++; + return count; } =20 @@ -652,17 +666,19 @@ static int i2c_hid_output_raw_report(struct hid_devic= e *hid, __u8 *buf, =20 mutex_lock(&ihid->reset_lock); =20 - if (report_id) { - buf++; - count--; - } - + /* + * Note that both numbered and unnumbered reports passed here + * are supposed to have report ID stored in the 1st byte of the + * buffer, so we strip it off unconditionally before passing payload + * to i2c_hid_set_or_send_report which takes care of encoding + * everything properly. + */ ret =3D i2c_hid_set_or_send_report(client, report_type =3D=3D HID_FEATURE_REPORT ? 0x03 : 0x02, - report_id, buf, count, use_data); + report_id, buf + 1, count - 1, use_data); =20 - if (report_id && ret >=3D 0) - ret++; /* add report_id to the number of transfered bytes */ + if (ret >=3D 0) + ret++; /* add report_id to the number of transferred bytes */ =20 mutex_unlock(&ihid->reset_lock); =20 diff --git a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c b/drivers/hid/inte= l-ish-hid/ishtp-fw-loader.c index 0e1183e96147..4f417d632bf1 100644 --- a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c +++ b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c @@ -660,21 +660,12 @@ static int ish_fw_xfer_direct_dma(struct ishtp_cl_dat= a *client_data, */ payload_max_size &=3D ~(L1_CACHE_BYTES - 1); =20 - dma_buf =3D kmalloc(payload_max_size, GFP_KERNEL | GFP_DMA32); + dma_buf =3D dma_alloc_coherent(devc, payload_max_size, &dma_buf_phy, GFP_= KERNEL); if (!dma_buf) { client_data->flag_retry =3D true; return -ENOMEM; } =20 - dma_buf_phy =3D dma_map_single(devc, dma_buf, payload_max_size, - DMA_TO_DEVICE); - if (dma_mapping_error(devc, dma_buf_phy)) { - dev_err(cl_data_to_dev(client_data), "DMA map failed\n"); - client_data->flag_retry =3D true; - rv =3D -ENOMEM; - goto end_err_dma_buf_release; - } - ldr_xfer_dma_frag.fragment.hdr.command =3D LOADER_CMD_XFER_FRAGMENT; ldr_xfer_dma_frag.fragment.xfer_mode =3D LOADER_XFER_MODE_DIRECT_DMA; ldr_xfer_dma_frag.ddr_phys_addr =3D (u64)dma_buf_phy; @@ -694,14 +685,7 @@ static int ish_fw_xfer_direct_dma(struct ishtp_cl_data= *client_data, ldr_xfer_dma_frag.fragment.size =3D fragment_size; memcpy(dma_buf, &fw->data[fragment_offset], fragment_size); =20 - dma_sync_single_for_device(devc, dma_buf_phy, - payload_max_size, - DMA_TO_DEVICE); - - /* - * Flush cache here because the dma_sync_single_for_device() - * does not do for x86. - */ + /* Flush cache to be sure the data is in main memory. */ clflush_cache_range(dma_buf, payload_max_size); =20 dev_dbg(cl_data_to_dev(client_data), @@ -724,15 +708,8 @@ static int ish_fw_xfer_direct_dma(struct ishtp_cl_data= *client_data, fragment_offset +=3D fragment_size; } =20 - dma_unmap_single(devc, dma_buf_phy, payload_max_size, DMA_TO_DEVICE); - kfree(dma_buf); - return 0; - end_err_resp_buf_release: - /* Free ISH buffer if not done already, in error case */ - dma_unmap_single(devc, dma_buf_phy, payload_max_size, DMA_TO_DEVICE); -end_err_dma_buf_release: - kfree(dma_buf); + dma_free_coherent(devc, payload_max_size, dma_buf, dma_buf_phy); return rv; } =20 diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index f2d05bff4245..439f99b8b5de 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -1563,7 +1563,7 @@ static void balloon_onchannelcallback(void *context) break; =20 default: - pr_warn("Unhandled message: type: %d\n", dm_hdr->type); + pr_warn_ratelimited("Unhandled message: type: %d\n", dm_hdr->type); =20 } } diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index e0aa8aa46d8c..ef3a8ecde4df 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -319,6 +319,7 @@ enum pmbus_fan_mode { percent =3D 0, rpm }; /* * STATUS_VOUT, STATUS_INPUT */ +#define PB_VOLTAGE_VIN_OFF BIT(3) #define PB_VOLTAGE_UV_FAULT BIT(4) #define PB_VOLTAGE_UV_WARNING BIT(5) #define PB_VOLTAGE_OV_WARNING BIT(6) diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_c= ore.c index ac2fbee1ba9c..ca0bfaf2f691 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -1373,7 +1373,7 @@ static const struct pmbus_limit_attr vin_limit_attrs[= ] =3D { .reg =3D PMBUS_VIN_UV_FAULT_LIMIT, .attr =3D "lcrit", .alarm =3D "lcrit_alarm", - .sbit =3D PB_VOLTAGE_UV_FAULT, + .sbit =3D PB_VOLTAGE_UV_FAULT | PB_VOLTAGE_VIN_OFF, }, { .reg =3D PMBUS_VIN_OV_WARN_LIMIT, .attr =3D "max", @@ -2391,10 +2391,14 @@ static int pmbus_regulator_is_enabled(struct regula= tor_dev *rdev) { struct device *dev =3D rdev_get_dev(rdev); struct i2c_client *client =3D to_i2c_client(dev->parent); + struct pmbus_data *data =3D i2c_get_clientdata(client); u8 page =3D rdev_get_id(rdev); int ret; =20 + mutex_lock(&data->update_lock); ret =3D pmbus_read_byte_data(client, page, PMBUS_OPERATION); + mutex_unlock(&data->update_lock); + if (ret < 0) return ret; =20 @@ -2405,11 +2409,17 @@ static int _pmbus_regulator_on_off(struct regulator= _dev *rdev, bool enable) { struct device *dev =3D rdev_get_dev(rdev); struct i2c_client *client =3D to_i2c_client(dev->parent); + struct pmbus_data *data =3D i2c_get_clientdata(client); u8 page =3D rdev_get_id(rdev); + int ret; =20 - return pmbus_update_byte_data(client, page, PMBUS_OPERATION, - PB_OPERATION_CONTROL_ON, - enable ? PB_OPERATION_CONTROL_ON : 0); + mutex_lock(&data->update_lock); + ret =3D pmbus_update_byte_data(client, page, PMBUS_OPERATION, + PB_OPERATION_CONTROL_ON, + enable ? PB_OPERATION_CONTROL_ON : 0); + mutex_unlock(&data->update_lock); + + return ret; } =20 static int pmbus_regulator_enable(struct regulator_dev *rdev) diff --git a/drivers/hwmon/sch56xx-common.c b/drivers/hwmon/sch56xx-common.c index 40cdadad35e5..f85eede6d766 100644 --- a/drivers/hwmon/sch56xx-common.c +++ b/drivers/hwmon/sch56xx-common.c @@ -422,7 +422,7 @@ void sch56xx_watchdog_register(struct device *parent, u= 16 addr, u32 revision, data->wddev.max_timeout =3D 255 * 60; watchdog_set_nowayout(&data->wddev, nowayout); if (output_enable & SCH56XX_WDOG_OUTPUT_ENABLE) - set_bit(WDOG_ACTIVE, &data->wddev.status); + set_bit(WDOG_HW_RUNNING, &data->wddev.status); =20 /* Since the watchdog uses a downcounter there is no register to read the BIOS set timeout from (if any was set at all) -> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/= hwtracing/coresight/coresight-etm4x-sysfs.c index a0640fa5c55b..57e94424a8d6 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c @@ -367,8 +367,12 @@ static ssize_t mode_store(struct device *dev, mode =3D ETM_MODE_QELEM(config->mode); /* start by clearing QE bits */ config->cfg &=3D ~(BIT(13) | BIT(14)); - /* if supported, Q elements with instruction counts are enabled */ - if ((mode & BIT(0)) && (drvdata->q_support & BIT(0))) + /* + * if supported, Q elements with instruction counts are enabled. + * Always set the low bit for any requested mode. Valid combos are + * 0b00, 0b01 and 0b11. + */ + if (mode && drvdata->q_support) config->cfg |=3D BIT(13); /* * if supported, Q elements with and without instruction diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtra= cing/coresight/coresight-syscfg.c index 43054568430f..c30989e0675f 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -791,7 +791,7 @@ static int cscfg_create_device(void) =20 err =3D device_register(dev); if (err) - cscfg_dev_release(dev); + put_device(dev); =20 create_dev_exit_unlock: mutex_unlock(&cscfg_mutex); diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2= 835.c index ad3b124a2e37..f72c6576d8a3 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -407,7 +407,7 @@ static const struct i2c_adapter_quirks bcm2835_i2c_quir= ks =3D { static int bcm2835_i2c_probe(struct platform_device *pdev) { struct bcm2835_i2c_dev *i2c_dev; - struct resource *mem, *irq; + struct resource *mem; int ret; struct i2c_adapter *adap; struct clk *mclk; @@ -454,21 +454,20 @@ static int bcm2835_i2c_probe(struct platform_device *= pdev) ret =3D clk_prepare_enable(i2c_dev->bus_clk); if (ret) { dev_err(&pdev->dev, "Couldn't prepare clock"); - return ret; + goto err_put_exclusive_rate; } =20 - irq =3D platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq) { - dev_err(&pdev->dev, "No IRQ resource\n"); - return -ENODEV; + i2c_dev->irq =3D platform_get_irq(pdev, 0); + if (i2c_dev->irq < 0) { + ret =3D i2c_dev->irq; + goto err_disable_unprepare_clk; } - i2c_dev->irq =3D irq->start; =20 ret =3D request_irq(i2c_dev->irq, bcm2835_i2c_isr, IRQF_SHARED, dev_name(&pdev->dev), i2c_dev); if (ret) { dev_err(&pdev->dev, "Could not request IRQ\n"); - return -ENODEV; + goto err_disable_unprepare_clk; } =20 adap =3D &i2c_dev->adapter; @@ -492,7 +491,16 @@ static int bcm2835_i2c_probe(struct platform_device *p= dev) =20 ret =3D i2c_add_adapter(adap); if (ret) - free_irq(i2c_dev->irq, i2c_dev); + goto err_free_irq; + + return 0; + +err_free_irq: + free_irq(i2c_dev->irq, i2c_dev); +err_disable_unprepare_clk: + clk_disable_unprepare(i2c_dev->bus_clk); +err_put_exclusive_rate: + clk_rate_exclusive_put(i2c_dev->bus_clk); =20 return ret; } diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index ef73a42577cc..07eb819072c4 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -465,18 +465,18 @@ static int meson_i2c_probe(struct platform_device *pd= ev) */ meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0); =20 - ret =3D i2c_add_adapter(&i2c->adap); - if (ret < 0) { - clk_disable_unprepare(i2c->clk); - return ret; - } - /* Disable filtering */ meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_SDA_FILTER | REG_SLV_SCL_FILTER, 0); =20 meson_i2c_set_clk_div(i2c, timings.bus_freq_hz); =20 + ret =3D i2c_add_adapter(&i2c->adap); + if (ret < 0) { + clk_disable_unprepare(i2c->clk); + return ret; + } + return 0; } =20 diff --git a/drivers/i2c/busses/i2c-pasemi-core.c b/drivers/i2c/busses/i2c-= pasemi-core.c index 4e161a4089d8..7728c8460dc0 100644 --- a/drivers/i2c/busses/i2c-pasemi-core.c +++ b/drivers/i2c/busses/i2c-pasemi-core.c @@ -333,7 +333,6 @@ int pasemi_i2c_common_probe(struct pasemi_smbus *smbus) smbus->adapter.owner =3D THIS_MODULE; snprintf(smbus->adapter.name, sizeof(smbus->adapter.name), "PA Semi SMBus adapter (%s)", dev_name(smbus->dev)); - smbus->adapter.class =3D I2C_CLASS_HWMON | I2C_CLASS_SPD; smbus->adapter.algo =3D &smbus_algorithm; smbus->adapter.algo_data =3D smbus; =20 diff --git a/drivers/i2c/busses/i2c-pasemi-pci.c b/drivers/i2c/busses/i2c-p= asemi-pci.c index 1ab1f28744fb..cfc89e04eb94 100644 --- a/drivers/i2c/busses/i2c-pasemi-pci.c +++ b/drivers/i2c/busses/i2c-pasemi-pci.c @@ -56,6 +56,7 @@ static int pasemi_smb_pci_probe(struct pci_dev *dev, if (!smbus->ioaddr) return -EBUSY; =20 + smbus->adapter.class =3D I2C_CLASS_HWMON | I2C_CLASS_SPD; error =3D pasemi_i2c_common_probe(smbus); if (error) return error; diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index eb789cfb9973..ffefe3c482e9 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -734,7 +734,6 @@ static const struct i2c_adapter_quirks xiic_quirks =3D { =20 static const struct i2c_adapter xiic_adapter =3D { .owner =3D THIS_MODULE, - .name =3D DRIVER_NAME, .class =3D I2C_CLASS_DEPRECATED, .algo =3D &xiic_algorithm, .quirks =3D &xiic_quirks, @@ -771,6 +770,8 @@ static int xiic_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(&i2c->adap, i2c); i2c->adap.dev.parent =3D &pdev->dev; i2c->adap.dev.of_node =3D pdev->dev.of_node; + snprintf(i2c->adap.name, sizeof(i2c->adap.name), + DRIVER_NAME " %s", pdev->name); =20 mutex_init(&i2c->lock); =20 diff --git a/drivers/i2c/muxes/i2c-demux-pinctrl.c b/drivers/i2c/muxes/i2c-= demux-pinctrl.c index 5365199a31f4..f7a7405d4350 100644 --- a/drivers/i2c/muxes/i2c-demux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-demux-pinctrl.c @@ -261,7 +261,7 @@ static int i2c_demux_pinctrl_probe(struct platform_devi= ce *pdev) =20 err =3D device_create_file(&pdev->dev, &dev_attr_available_masters); if (err) - goto err_rollback; + goto err_rollback_activation; =20 err =3D device_create_file(&pdev->dev, &dev_attr_current_master); if (err) @@ -271,8 +271,9 @@ static int i2c_demux_pinctrl_probe(struct platform_devi= ce *pdev) =20 err_rollback_available: device_remove_file(&pdev->dev, &dev_attr_available_masters); -err_rollback: +err_rollback_activation: i2c_demux_deactivate_master(priv); +err_rollback: for (j =3D 0; j < i; j++) { of_node_put(priv->chan[j].parent_np); of_changeset_destroy(&priv->chan[j].chgset); diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 09c7f10fefb6..21a99467f364 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -176,6 +176,7 @@ static const struct mma8452_event_regs trans_ev_regs = =3D { * @enabled_events: event flags enabled and handled by this driver */ struct mma_chip_info { + const char *name; u8 chip_id; const struct iio_chan_spec *channels; int num_channels; @@ -1301,6 +1302,7 @@ enum { =20 static const struct mma_chip_info mma_chip_info_table[] =3D { [mma8451] =3D { + .name =3D "mma8451", .chip_id =3D MMA8451_DEVICE_ID, .channels =3D mma8451_channels, .num_channels =3D ARRAY_SIZE(mma8451_channels), @@ -1325,6 +1327,7 @@ static const struct mma_chip_info mma_chip_info_table= [] =3D { MMA8452_INT_FF_MT, }, [mma8452] =3D { + .name =3D "mma8452", .chip_id =3D MMA8452_DEVICE_ID, .channels =3D mma8452_channels, .num_channels =3D ARRAY_SIZE(mma8452_channels), @@ -1341,6 +1344,7 @@ static const struct mma_chip_info mma_chip_info_table= [] =3D { MMA8452_INT_FF_MT, }, [mma8453] =3D { + .name =3D "mma8453", .chip_id =3D MMA8453_DEVICE_ID, .channels =3D mma8453_channels, .num_channels =3D ARRAY_SIZE(mma8453_channels), @@ -1357,6 +1361,7 @@ static const struct mma_chip_info mma_chip_info_table= [] =3D { MMA8452_INT_FF_MT, }, [mma8652] =3D { + .name =3D "mma8652", .chip_id =3D MMA8652_DEVICE_ID, .channels =3D mma8652_channels, .num_channels =3D ARRAY_SIZE(mma8652_channels), @@ -1366,6 +1371,7 @@ static const struct mma_chip_info mma_chip_info_table= [] =3D { .enabled_events =3D MMA8452_INT_FF_MT, }, [mma8653] =3D { + .name =3D "mma8653", .chip_id =3D MMA8653_DEVICE_ID, .channels =3D mma8653_channels, .num_channels =3D ARRAY_SIZE(mma8653_channels), @@ -1380,6 +1386,7 @@ static const struct mma_chip_info mma_chip_info_table= [] =3D { .enabled_events =3D MMA8452_INT_FF_MT, }, [fxls8471] =3D { + .name =3D "fxls8471", .chip_id =3D FXLS8471_DEVICE_ID, .channels =3D mma8451_channels, .num_channels =3D ARRAY_SIZE(mma8451_channels), @@ -1522,13 +1529,6 @@ static int mma8452_probe(struct i2c_client *client, struct mma8452_data *data; struct iio_dev *indio_dev; int ret; - const struct of_device_id *match; - - match =3D of_match_device(mma8452_dt_ids, &client->dev); - if (!match) { - dev_err(&client->dev, "unknown device model\n"); - return -ENODEV; - } =20 indio_dev =3D devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -1537,7 +1537,14 @@ static int mma8452_probe(struct i2c_client *client, data =3D iio_priv(indio_dev); data->client =3D client; mutex_init(&data->lock); - data->chip_info =3D match->data; + + data->chip_info =3D device_get_match_data(&client->dev); + if (!data->chip_info && id) { + data->chip_info =3D &mma_chip_info_table[id->driver_data]; + } else { + dev_err(&client->dev, "unknown device model\n"); + return -ENODEV; + } =20 data->vdd_reg =3D devm_regulator_get(&client->dev, "vdd"); if (IS_ERR(data->vdd_reg)) @@ -1581,11 +1588,11 @@ static int mma8452_probe(struct i2c_client *client, } =20 dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n", - match->compatible, data->chip_info->chip_id); + data->chip_info->name, data->chip_info->chip_id); =20 i2c_set_clientdata(client, indio_dev); indio_dev->info =3D &mma8452_info; - indio_dev->name =3D id->name; + indio_dev->name =3D data->chip_info->name; indio_dev->modes =3D INDIO_DIRECT_MODE; indio_dev->channels =3D data->chip_info->channels; indio_dev->num_channels =3D data->chip_info->num_channels; @@ -1810,7 +1817,7 @@ MODULE_DEVICE_TABLE(i2c, mma8452_id); static struct i2c_driver mma8452_driver =3D { .driver =3D { .name =3D "mma8452", - .of_match_table =3D of_match_ptr(mma8452_dt_ids), + .of_match_table =3D mma8452_dt_ids, .pm =3D &mma8452_pm_ops, }, .probe =3D mma8452_probe, diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c index e939b84cbb56..0793d2474cdc 100644 --- a/drivers/iio/adc/aspeed_adc.c +++ b/drivers/iio/adc/aspeed_adc.c @@ -539,7 +539,9 @@ static int aspeed_adc_probe(struct platform_device *pde= v) data->clk_scaler =3D devm_clk_hw_register_divider( &pdev->dev, clk_name, clk_parent_name, scaler_flags, data->base + ASPEED_REG_CLOCK_CONTROL, 0, - data->model_data->scaler_bit_width, 0, &data->clk_lock); + data->model_data->scaler_bit_width, + data->model_data->need_prescaler ? CLK_DIVIDER_ONE_BASED : 0, + &data->clk_lock); if (IS_ERR(data->clk_scaler)) return PTR_ERR(data->clk_scaler); =20 diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpad= c.c index afdb59e0b526..d0223e39d59a 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -911,6 +911,8 @@ static int twl6030_gpadc_probe(struct platform_device *= pdev) ret =3D devm_request_threaded_irq(dev, irq, NULL, twl6030_gpadc_irq_handler, IRQF_ONESHOT, "twl6030_gpadc", indio_dev); + if (ret) + return ret; =20 ret =3D twl6030_gpadc_enable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK); if (ret < 0) { diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index 774eb3044edd..271d73e420c4 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c @@ -39,7 +39,7 @@ static int rescale_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct rescale *rescale =3D iio_priv(indio_dev); - unsigned long long tmp; + s64 tmp; int ret; =20 switch (mask) { @@ -77,10 +77,10 @@ static int rescale_read_raw(struct iio_dev *indio_dev, *val2 =3D rescale->denominator; return IIO_VAL_FRACTIONAL; case IIO_VAL_FRACTIONAL_LOG2: - tmp =3D *val * 1000000000LL; - do_div(tmp, rescale->denominator); + tmp =3D (s64)*val * 1000000000LL; + tmp =3D div_s64(tmp, rescale->denominator); tmp *=3D rescale->numerator; - do_div(tmp, 1000000000LL); + tmp =3D div_s64(tmp, 1000000000LL); *val =3D tmp; return ret; default: diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 0222885b334c..df74765d33dc 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -595,28 +595,50 @@ EXPORT_SYMBOL_GPL(iio_read_channel_average_raw); static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan, int raw, int *processed, unsigned int scale) { - int scale_type, scale_val, scale_val2, offset; + int scale_type, scale_val, scale_val2; + int offset_type, offset_val, offset_val2; s64 raw64 =3D raw; - int ret; =20 - ret =3D iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_OFFSET); - if (ret >=3D 0) - raw64 +=3D offset; + offset_type =3D iio_channel_read(chan, &offset_val, &offset_val2, + IIO_CHAN_INFO_OFFSET); + if (offset_type >=3D 0) { + switch (offset_type) { + case IIO_VAL_INT: + break; + case IIO_VAL_INT_PLUS_MICRO: + case IIO_VAL_INT_PLUS_NANO: + /* + * Both IIO_VAL_INT_PLUS_MICRO and IIO_VAL_INT_PLUS_NANO + * implicitely truncate the offset to it's integer form. + */ + break; + case IIO_VAL_FRACTIONAL: + offset_val /=3D offset_val2; + break; + case IIO_VAL_FRACTIONAL_LOG2: + offset_val >>=3D offset_val2; + break; + default: + return -EINVAL; + } + + raw64 +=3D offset_val; + } =20 scale_type =3D iio_channel_read(chan, &scale_val, &scale_val2, IIO_CHAN_INFO_SCALE); if (scale_type < 0) { /* - * Just pass raw values as processed if no scaling is - * available. + * If no channel scaling is available apply consumer scale to + * raw value and return. */ - *processed =3D raw; + *processed =3D raw * scale; return 0; } =20 switch (scale_type) { case IIO_VAL_INT: - *processed =3D raw64 * scale_val; + *processed =3D raw64 * scale_val * scale; break; case IIO_VAL_INT_PLUS_MICRO: if (scale_val2 < 0) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 41ec05c4b0d0..80a8e31e5b38 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2642,7 +2642,7 @@ int rdma_set_ack_timeout(struct rdma_cm_id *id, u8 ti= meout) { struct rdma_id_private *id_priv; =20 - if (id->qp_type !=3D IB_QPT_RC) + if (id->qp_type !=3D IB_QPT_RC && id->qp_type !=3D IB_QPT_XRC_INI) return -EINVAL; =20 id_priv =3D container_of(id, struct rdma_id_private, id); diff --git a/drivers/infiniband/core/nldev.c b/drivers/infiniband/core/nlde= v.c index f5aacaf7fb8e..ca24ce34da76 100644 --- a/drivers/infiniband/core/nldev.c +++ b/drivers/infiniband/core/nldev.c @@ -1951,9 +1951,10 @@ static int nldev_stat_set_counter_dynamic_doit(struc= t nlattr *tb[], u32 port) { struct rdma_hw_stats *stats; - int rem, i, index, ret =3D 0; struct nlattr *entry_attr; unsigned long *target; + int rem, i, ret =3D 0; + u32 index; =20 stats =3D ib_get_hw_stats_port(device, port); if (!stats) diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verb= s.c index c18634bec212..e821dc94a43e 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -2153,6 +2153,7 @@ struct ib_mr *ib_reg_user_mr(struct ib_pd *pd, u64 st= art, u64 length, return mr; =20 mr->device =3D pd->device; + mr->type =3D IB_MR_TYPE_USER; mr->pd =3D pd; mr->dm =3D NULL; atomic_inc(&pd->usecnt); diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi= 1/verbs.c index dc9211f3a009..99d0743133ca 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -1397,8 +1397,7 @@ static int query_port(struct rvt_dev_info *rdi, u32 p= ort_num, 4096 : hfi1_max_mtu), IB_MTU_4096); props->active_mtu =3D !valid_ib_mtu(ppd->ibmtu) ? props->max_mtu : mtu_to_enum(ppd->ibmtu, IB_MTU_4096); - props->phys_mtu =3D HFI1_CAP_IS_KSET(AIP) ? hfi1_max_mtu : - ib_mtu_enum_to_int(props->max_mtu); + props->phys_mtu =3D hfi1_max_mtu; =20 return 0; } diff --git a/drivers/infiniband/hw/irdma/ctrl.c b/drivers/infiniband/hw/ird= ma/ctrl.c index 7264f8c2f7d5..1d6b578dbd82 100644 --- a/drivers/infiniband/hw/irdma/ctrl.c +++ b/drivers/infiniband/hw/irdma/ctrl.c @@ -431,7 +431,7 @@ enum irdma_status_code irdma_sc_qp_create(struct irdma_= sc_qp *qp, struct irdma_c =20 cqp =3D qp->dev->cqp; if (qp->qp_uk.qp_id < cqp->dev->hw_attrs.min_hw_qp_id || - qp->qp_uk.qp_id > (cqp->dev->hmc_info->hmc_obj[IRDMA_HMC_IW_QP].max_c= nt - 1)) + qp->qp_uk.qp_id >=3D (cqp->dev->hmc_info->hmc_obj[IRDMA_HMC_IW_QP].ma= x_cnt)) return IRDMA_ERR_INVALID_QP_ID; =20 wqe =3D irdma_sc_cqp_get_next_send_wqe(cqp, scratch); @@ -2510,10 +2510,10 @@ static enum irdma_status_code irdma_sc_cq_create(st= ruct irdma_sc_cq *cq, enum irdma_status_code ret_code =3D 0; =20 cqp =3D cq->dev->cqp; - if (cq->cq_uk.cq_id > (cqp->dev->hmc_info->hmc_obj[IRDMA_HMC_IW_CQ].max_c= nt - 1)) + if (cq->cq_uk.cq_id >=3D (cqp->dev->hmc_info->hmc_obj[IRDMA_HMC_IW_CQ].ma= x_cnt)) return IRDMA_ERR_INVALID_CQ_ID; =20 - if (cq->ceq_id > (cq->dev->hmc_fpm_misc.max_ceqs - 1)) + if (cq->ceq_id >=3D (cq->dev->hmc_fpm_misc.max_ceqs)) return IRDMA_ERR_INVALID_CEQ_ID; =20 ceq =3D cq->dev->ceq[cq->ceq_id]; @@ -3615,7 +3615,7 @@ enum irdma_status_code irdma_sc_ceq_init(struct irdma= _sc_ceq *ceq, info->elem_cnt > info->dev->hw_attrs.max_hw_ceq_size) return IRDMA_ERR_INVALID_SIZE; =20 - if (info->ceq_id > (info->dev->hmc_fpm_misc.max_ceqs - 1)) + if (info->ceq_id >=3D (info->dev->hmc_fpm_misc.max_ceqs)) return IRDMA_ERR_INVALID_CEQ_ID; pble_obj_cnt =3D info->dev->hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].cnt; =20 @@ -4164,7 +4164,7 @@ enum irdma_status_code irdma_sc_ccq_init(struct irdma= _sc_cq *cq, info->num_elem > info->dev->hw_attrs.uk_attrs.max_hw_cq_size) return IRDMA_ERR_INVALID_SIZE; =20 - if (info->ceq_id > (info->dev->hmc_fpm_misc.max_ceqs - 1)) + if (info->ceq_id >=3D (info->dev->hmc_fpm_misc.max_ceqs )) return IRDMA_ERR_INVALID_CEQ_ID; =20 pble_obj_cnt =3D info->dev->hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].cnt; diff --git a/drivers/infiniband/hw/irdma/hw.c b/drivers/infiniband/hw/irdma= /hw.c index b4c657f5f2f9..f99c40893ffa 100644 --- a/drivers/infiniband/hw/irdma/hw.c +++ b/drivers/infiniband/hw/irdma/hw.c @@ -1608,7 +1608,7 @@ static enum irdma_status_code irdma_initialize_dev(st= ruct irdma_pci_f *rf) info.fpm_commit_buf =3D mem.va; =20 info.bar0 =3D rf->hw.hw_addr; - info.hmc_fn_id =3D PCI_FUNC(rf->pcidev->devfn); + info.hmc_fn_id =3D rf->pf_id; info.hw =3D &rf->hw; status =3D irdma_sc_dev_init(rf->rdma_ver, &rf->sc_dev, &info); if (status) diff --git a/drivers/infiniband/hw/irdma/i40iw_if.c b/drivers/infiniband/hw= /irdma/i40iw_if.c index d219f64b2c3d..a6f758b61b0c 100644 --- a/drivers/infiniband/hw/irdma/i40iw_if.c +++ b/drivers/infiniband/hw/irdma/i40iw_if.c @@ -77,6 +77,7 @@ static void i40iw_fill_device_info(struct irdma_device *i= wdev, struct i40e_info rf->rdma_ver =3D IRDMA_GEN_1; rf->gen_ops.request_reset =3D i40iw_request_reset; rf->pcidev =3D cdev_info->pcidev; + rf->pf_id =3D cdev_info->fid; rf->hw.hw_addr =3D cdev_info->hw_addr; rf->cdev =3D cdev_info; rf->msix_count =3D cdev_info->msix_count; diff --git a/drivers/infiniband/hw/irdma/main.c b/drivers/infiniband/hw/ird= ma/main.c index 51a41359e0b4..c556a36e7670 100644 --- a/drivers/infiniband/hw/irdma/main.c +++ b/drivers/infiniband/hw/irdma/main.c @@ -226,6 +226,7 @@ static void irdma_fill_device_info(struct irdma_device = *iwdev, struct ice_pf *pf rf->hw.hw_addr =3D pf->hw.hw_addr; rf->pcidev =3D pf->pdev; rf->msix_count =3D pf->num_rdma_msix; + rf->pf_id =3D pf->hw.pf_id; rf->msix_entries =3D &pf->msix_entries[pf->rdma_base_vector]; rf->default_vsi.vsi_idx =3D vsi->vsi_num; rf->protocol_used =3D IRDMA_ROCE_PROTOCOL_ONLY; diff --git a/drivers/infiniband/hw/irdma/main.h b/drivers/infiniband/hw/ird= ma/main.h index cb218cab79ac..fb7faa85e4c9 100644 --- a/drivers/infiniband/hw/irdma/main.h +++ b/drivers/infiniband/hw/irdma/main.h @@ -257,6 +257,7 @@ struct irdma_pci_f { u8 *mem_rsrc; u8 rdma_ver; u8 rst_to; + u8 pf_id; enum irdma_protocol_used protocol_used; u32 sd_type; u32 msix_count; diff --git a/drivers/infiniband/hw/irdma/utils.c b/drivers/infiniband/hw/ir= dma/utils.c index 398736d8c78a..e81b74a518dd 100644 --- a/drivers/infiniband/hw/irdma/utils.c +++ b/drivers/infiniband/hw/irdma/utils.c @@ -150,31 +150,35 @@ int irdma_inetaddr_event(struct notifier_block *notif= ier, unsigned long event, void *ptr) { struct in_ifaddr *ifa =3D ptr; - struct net_device *netdev =3D ifa->ifa_dev->dev; + struct net_device *real_dev, *netdev =3D ifa->ifa_dev->dev; struct irdma_device *iwdev; struct ib_device *ibdev; u32 local_ipaddr; =20 - ibdev =3D ib_device_get_by_netdev(netdev, RDMA_DRIVER_IRDMA); + real_dev =3D rdma_vlan_dev_real_dev(netdev); + if (!real_dev) + real_dev =3D netdev; + + ibdev =3D ib_device_get_by_netdev(real_dev, RDMA_DRIVER_IRDMA); if (!ibdev) return NOTIFY_DONE; =20 iwdev =3D to_iwdev(ibdev); local_ipaddr =3D ntohl(ifa->ifa_address); ibdev_dbg(&iwdev->ibdev, - "DEV: netdev %p event %lu local_ip=3D%pI4 MAC=3D%pM\n", netdev, - event, &local_ipaddr, netdev->dev_addr); + "DEV: netdev %p event %lu local_ip=3D%pI4 MAC=3D%pM\n", real_dev, + event, &local_ipaddr, real_dev->dev_addr); switch (event) { case NETDEV_DOWN: - irdma_manage_arp_cache(iwdev->rf, netdev->dev_addr, + irdma_manage_arp_cache(iwdev->rf, real_dev->dev_addr, &local_ipaddr, true, IRDMA_ARP_DELETE); - irdma_if_notify(iwdev, netdev, &local_ipaddr, true, false); + irdma_if_notify(iwdev, real_dev, &local_ipaddr, true, false); irdma_gid_change_event(&iwdev->ibdev); break; case NETDEV_UP: case NETDEV_CHANGEADDR: - irdma_add_arp(iwdev->rf, &local_ipaddr, true, netdev->dev_addr); - irdma_if_notify(iwdev, netdev, &local_ipaddr, true, true); + irdma_add_arp(iwdev->rf, &local_ipaddr, true, real_dev->dev_addr); + irdma_if_notify(iwdev, real_dev, &local_ipaddr, true, true); irdma_gid_change_event(&iwdev->ibdev); break; default: @@ -196,32 +200,36 @@ int irdma_inet6addr_event(struct notifier_block *noti= fier, unsigned long event, void *ptr) { struct inet6_ifaddr *ifa =3D ptr; - struct net_device *netdev =3D ifa->idev->dev; + struct net_device *real_dev, *netdev =3D ifa->idev->dev; struct irdma_device *iwdev; struct ib_device *ibdev; u32 local_ipaddr6[4]; =20 - ibdev =3D ib_device_get_by_netdev(netdev, RDMA_DRIVER_IRDMA); + real_dev =3D rdma_vlan_dev_real_dev(netdev); + if (!real_dev) + real_dev =3D netdev; + + ibdev =3D ib_device_get_by_netdev(real_dev, RDMA_DRIVER_IRDMA); if (!ibdev) return NOTIFY_DONE; =20 iwdev =3D to_iwdev(ibdev); irdma_copy_ip_ntohl(local_ipaddr6, ifa->addr.in6_u.u6_addr32); ibdev_dbg(&iwdev->ibdev, - "DEV: netdev %p event %lu local_ip=3D%pI6 MAC=3D%pM\n", netdev, - event, local_ipaddr6, netdev->dev_addr); + "DEV: netdev %p event %lu local_ip=3D%pI6 MAC=3D%pM\n", real_dev, + event, local_ipaddr6, real_dev->dev_addr); switch (event) { case NETDEV_DOWN: - irdma_manage_arp_cache(iwdev->rf, netdev->dev_addr, + irdma_manage_arp_cache(iwdev->rf, real_dev->dev_addr, local_ipaddr6, false, IRDMA_ARP_DELETE); - irdma_if_notify(iwdev, netdev, local_ipaddr6, false, false); + irdma_if_notify(iwdev, real_dev, local_ipaddr6, false, false); irdma_gid_change_event(&iwdev->ibdev); break; case NETDEV_UP: case NETDEV_CHANGEADDR: irdma_add_arp(iwdev->rf, local_ipaddr6, false, - netdev->dev_addr); - irdma_if_notify(iwdev, netdev, local_ipaddr6, false, true); + real_dev->dev_addr); + irdma_if_notify(iwdev, real_dev, local_ipaddr6, false, true); irdma_gid_change_event(&iwdev->ibdev); break; default: @@ -243,14 +251,18 @@ int irdma_net_event(struct notifier_block *notifier, = unsigned long event, void *ptr) { struct neighbour *neigh =3D ptr; + struct net_device *real_dev, *netdev =3D (struct net_device *)neigh->dev; struct irdma_device *iwdev; struct ib_device *ibdev; __be32 *p; u32 local_ipaddr[4] =3D {}; bool ipv4 =3D true; =20 - ibdev =3D ib_device_get_by_netdev((struct net_device *)neigh->dev, - RDMA_DRIVER_IRDMA); + real_dev =3D rdma_vlan_dev_real_dev(netdev); + if (!real_dev) + real_dev =3D netdev; + + ibdev =3D ib_device_get_by_netdev(real_dev, RDMA_DRIVER_IRDMA); if (!ibdev) return NOTIFY_DONE; =20 diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/ir= dma/verbs.c index 8cd5f9261692..03d4da16604d 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -2504,7 +2504,7 @@ static int irdma_dealloc_mw(struct ib_mw *ibmw) cqp_info =3D &cqp_request->info; info =3D &cqp_info->in.u.dealloc_stag.info; memset(info, 0, sizeof(*info)); - info->pd_id =3D iwpd->sc_pd.pd_id & 0x00007fff; + info->pd_id =3D iwpd->sc_pd.pd_id; info->stag_idx =3D ibmw->rkey >> IRDMA_CQPSQ_STAG_IDX_S; info->mr =3D false; cqp_info->cqp_cmd =3D IRDMA_OP_DEALLOC_STAG; @@ -3016,7 +3016,7 @@ static int irdma_dereg_mr(struct ib_mr *ib_mr, struct= ib_udata *udata) cqp_info =3D &cqp_request->info; info =3D &cqp_info->in.u.dealloc_stag.info; memset(info, 0, sizeof(*info)); - info->pd_id =3D iwpd->sc_pd.pd_id & 0x00007fff; + info->pd_id =3D iwpd->sc_pd.pd_id; info->stag_idx =3D ib_mr->rkey >> IRDMA_CQPSQ_STAG_IDX_S; info->mr =3D true; if (iwpbl->pbl_allocated) diff --git a/drivers/infiniband/hw/mlx5/devx.c b/drivers/infiniband/hw/mlx5= /devx.c index 08b7f6bc56c3..15c0884d1f49 100644 --- a/drivers/infiniband/hw/mlx5/devx.c +++ b/drivers/infiniband/hw/mlx5/devx.c @@ -1886,8 +1886,10 @@ subscribe_event_xa_alloc(struct mlx5_devx_event_tabl= e *devx_event_table, key_level2, obj_event, GFP_KERNEL); - if (err) + if (err) { + kfree(obj_event); return err; + } INIT_LIST_HEAD(&obj_event->obj_sub_list); } =20 diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/m= r.c index 157d862fb864..2910d7833313 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -585,6 +585,8 @@ struct mlx5_ib_mr *mlx5_mr_cache_alloc(struct mlx5_ib_d= ev *dev, ent =3D &cache->ent[entry]; spin_lock_irq(&ent->lock); if (list_empty(&ent->head)) { + queue_adjust_cache_locked(ent); + ent->miss++; spin_unlock_irq(&ent->lock); mr =3D create_cache_mr(ent); if (IS_ERR(mr)) diff --git a/drivers/infiniband/sw/rxe/rxe_av.c b/drivers/infiniband/sw/rxe= /rxe_av.c index 38c7b6fb39d7..360a567159fe 100644 --- a/drivers/infiniband/sw/rxe/rxe_av.c +++ b/drivers/infiniband/sw/rxe/rxe_av.c @@ -99,11 +99,14 @@ void rxe_av_fill_ip_info(struct rxe_av *av, struct rdma= _ah_attr *attr) av->network_type =3D type; } =20 -struct rxe_av *rxe_get_av(struct rxe_pkt_info *pkt) +struct rxe_av *rxe_get_av(struct rxe_pkt_info *pkt, struct rxe_ah **ahp) { struct rxe_ah *ah; u32 ah_num; =20 + if (ahp) + *ahp =3D NULL; + if (!pkt || !pkt->qp) return NULL; =20 @@ -117,10 +120,22 @@ struct rxe_av *rxe_get_av(struct rxe_pkt_info *pkt) if (ah_num) { /* only new user provider or kernel client */ ah =3D rxe_pool_get_index(&pkt->rxe->ah_pool, ah_num); - if (!ah || ah->ah_num !=3D ah_num || rxe_ah_pd(ah) !=3D pkt->qp->pd) { + if (!ah) { pr_warn("Unable to find AH matching ah_num\n"); return NULL; } + + if (rxe_ah_pd(ah) !=3D pkt->qp->pd) { + pr_warn("PDs don't match for AH and QP\n"); + rxe_drop_ref(ah); + return NULL; + } + + if (ahp) + *ahp =3D ah; + else + rxe_drop_ref(ah); + return &ah->av; } =20 diff --git a/drivers/infiniband/sw/rxe/rxe_loc.h b/drivers/infiniband/sw/rx= e/rxe_loc.h index 1ca43b859d80..42234744dadd 100644 --- a/drivers/infiniband/sw/rxe/rxe_loc.h +++ b/drivers/infiniband/sw/rxe/rxe_loc.h @@ -19,7 +19,7 @@ void rxe_av_to_attr(struct rxe_av *av, struct rdma_ah_att= r *attr); =20 void rxe_av_fill_ip_info(struct rxe_av *av, struct rdma_ah_attr *attr); =20 -struct rxe_av *rxe_get_av(struct rxe_pkt_info *pkt); +struct rxe_av *rxe_get_av(struct rxe_pkt_info *pkt, struct rxe_ah **ahp); =20 /* rxe_cq.c */ int rxe_cq_chk_attr(struct rxe_dev *rxe, struct rxe_cq *cq, @@ -102,7 +102,8 @@ void rxe_mw_cleanup(struct rxe_pool_entry *arg); /* rxe_net.c */ struct sk_buff *rxe_init_packet(struct rxe_dev *rxe, struct rxe_av *av, int paylen, struct rxe_pkt_info *pkt); -int rxe_prepare(struct rxe_pkt_info *pkt, struct sk_buff *skb); +int rxe_prepare(struct rxe_av *av, struct rxe_pkt_info *pkt, + struct sk_buff *skb); int rxe_xmit_packet(struct rxe_qp *qp, struct rxe_pkt_info *pkt, struct sk_buff *skb); const char *rxe_parent_name(struct rxe_dev *rxe, unsigned int port_num); diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rx= e/rxe_net.c index 2cb810cb890a..456e960cacd7 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.c +++ b/drivers/infiniband/sw/rxe/rxe_net.c @@ -293,13 +293,13 @@ static void prepare_ipv6_hdr(struct dst_entry *dst, s= truct sk_buff *skb, ip6h->payload_len =3D htons(skb->len - sizeof(*ip6h)); } =20 -static int prepare4(struct rxe_pkt_info *pkt, struct sk_buff *skb) +static int prepare4(struct rxe_av *av, struct rxe_pkt_info *pkt, + struct sk_buff *skb) { struct rxe_qp *qp =3D pkt->qp; struct dst_entry *dst; bool xnet =3D false; __be16 df =3D htons(IP_DF); - struct rxe_av *av =3D rxe_get_av(pkt); struct in_addr *saddr =3D &av->sgid_addr._sockaddr_in.sin_addr; struct in_addr *daddr =3D &av->dgid_addr._sockaddr_in.sin_addr; =20 @@ -319,11 +319,11 @@ static int prepare4(struct rxe_pkt_info *pkt, struct = sk_buff *skb) return 0; } =20 -static int prepare6(struct rxe_pkt_info *pkt, struct sk_buff *skb) +static int prepare6(struct rxe_av *av, struct rxe_pkt_info *pkt, + struct sk_buff *skb) { struct rxe_qp *qp =3D pkt->qp; struct dst_entry *dst; - struct rxe_av *av =3D rxe_get_av(pkt); struct in6_addr *saddr =3D &av->sgid_addr._sockaddr_in6.sin6_addr; struct in6_addr *daddr =3D &av->dgid_addr._sockaddr_in6.sin6_addr; =20 @@ -344,16 +344,17 @@ static int prepare6(struct rxe_pkt_info *pkt, struct = sk_buff *skb) return 0; } =20 -int rxe_prepare(struct rxe_pkt_info *pkt, struct sk_buff *skb) +int rxe_prepare(struct rxe_av *av, struct rxe_pkt_info *pkt, + struct sk_buff *skb) { int err =3D 0; =20 if (skb->protocol =3D=3D htons(ETH_P_IP)) - err =3D prepare4(pkt, skb); + err =3D prepare4(av, pkt, skb); else if (skb->protocol =3D=3D htons(ETH_P_IPV6)) - err =3D prepare6(pkt, skb); + err =3D prepare6(av, pkt, skb); =20 - if (ether_addr_equal(skb->dev->dev_addr, rxe_get_av(pkt)->dmac)) + if (ether_addr_equal(skb->dev->dev_addr, av->dmac)) pkt->mask |=3D RXE_LOOPBACK_MASK; =20 return err; diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rx= e/rxe_req.c index 0c9d2af15f3d..ae2a02f3d335 100644 --- a/drivers/infiniband/sw/rxe/rxe_req.c +++ b/drivers/infiniband/sw/rxe/rxe_req.c @@ -361,14 +361,14 @@ static inline int get_mtu(struct rxe_qp *qp) } =20 static struct sk_buff *init_req_packet(struct rxe_qp *qp, + struct rxe_av *av, struct rxe_send_wqe *wqe, - int opcode, int payload, + int opcode, u32 payload, struct rxe_pkt_info *pkt) { struct rxe_dev *rxe =3D to_rdev(qp->ibqp.device); struct sk_buff *skb; struct rxe_send_wr *ibwr =3D &wqe->wr; - struct rxe_av *av; int pad =3D (-payload) & 0x3; int paylen; int solicited; @@ -378,21 +378,9 @@ static struct sk_buff *init_req_packet(struct rxe_qp *= qp, =20 /* length from start of bth to end of icrc */ paylen =3D rxe_opcode[opcode].length + payload + pad + RXE_ICRC_SIZE; - - /* pkt->hdr, port_num and mask are initialized in ifc layer */ - pkt->rxe =3D rxe; - pkt->opcode =3D opcode; - pkt->qp =3D qp; - pkt->psn =3D qp->req.psn; - pkt->mask =3D rxe_opcode[opcode].mask; - pkt->paylen =3D paylen; - pkt->wqe =3D wqe; + pkt->paylen =3D paylen; =20 /* init skb */ - av =3D rxe_get_av(pkt); - if (!av) - return NULL; - skb =3D rxe_init_packet(rxe, av, paylen, pkt); if (unlikely(!skb)) return NULL; @@ -453,13 +441,13 @@ static struct sk_buff *init_req_packet(struct rxe_qp = *qp, return skb; } =20 -static int finish_packet(struct rxe_qp *qp, struct rxe_send_wqe *wqe, - struct rxe_pkt_info *pkt, struct sk_buff *skb, - int paylen) +static int finish_packet(struct rxe_qp *qp, struct rxe_av *av, + struct rxe_send_wqe *wqe, struct rxe_pkt_info *pkt, + struct sk_buff *skb, u32 paylen) { int err; =20 - err =3D rxe_prepare(pkt, skb); + err =3D rxe_prepare(av, pkt, skb); if (err) return err; =20 @@ -503,7 +491,7 @@ static void update_wqe_state(struct rxe_qp *qp, static void update_wqe_psn(struct rxe_qp *qp, struct rxe_send_wqe *wqe, struct rxe_pkt_info *pkt, - int payload) + u32 payload) { /* number of packets left to send including current one */ int num_pkt =3D (wqe->dma.resid + payload + qp->mtu - 1) / qp->mtu; @@ -546,7 +534,7 @@ static void rollback_state(struct rxe_send_wqe *wqe, } =20 static void update_state(struct rxe_qp *qp, struct rxe_send_wqe *wqe, - struct rxe_pkt_info *pkt, int payload) + struct rxe_pkt_info *pkt, u32 payload) { qp->req.opcode =3D pkt->opcode; =20 @@ -614,17 +602,20 @@ static int rxe_do_local_ops(struct rxe_qp *qp, struct= rxe_send_wqe *wqe) int rxe_requester(void *arg) { struct rxe_qp *qp =3D (struct rxe_qp *)arg; + struct rxe_dev *rxe =3D to_rdev(qp->ibqp.device); struct rxe_pkt_info pkt; struct sk_buff *skb; struct rxe_send_wqe *wqe; enum rxe_hdr_mask mask; - int payload; + u32 payload; int mtu; int opcode; int ret; struct rxe_send_wqe rollback_wqe; u32 rollback_psn; struct rxe_queue *q =3D qp->sq.queue; + struct rxe_ah *ah; + struct rxe_av *av; =20 rxe_add_ref(qp); =20 @@ -711,14 +702,28 @@ int rxe_requester(void *arg) payload =3D mtu; } =20 - skb =3D init_req_packet(qp, wqe, opcode, payload, &pkt); + pkt.rxe =3D rxe; + pkt.opcode =3D opcode; + pkt.qp =3D qp; + pkt.psn =3D qp->req.psn; + pkt.mask =3D rxe_opcode[opcode].mask; + pkt.wqe =3D wqe; + + av =3D rxe_get_av(&pkt, &ah); + if (unlikely(!av)) { + pr_err("qp#%d Failed no address vector\n", qp_num(qp)); + wqe->status =3D IB_WC_LOC_QP_OP_ERR; + goto err_drop_ah; + } + + skb =3D init_req_packet(qp, av, wqe, opcode, payload, &pkt); if (unlikely(!skb)) { pr_err("qp#%d Failed allocating skb\n", qp_num(qp)); wqe->status =3D IB_WC_LOC_QP_OP_ERR; - goto err; + goto err_drop_ah; } =20 - ret =3D finish_packet(qp, wqe, &pkt, skb, payload); + ret =3D finish_packet(qp, av, wqe, &pkt, skb, payload); if (unlikely(ret)) { pr_debug("qp#%d Error during finish packet\n", qp_num(qp)); if (ret =3D=3D -EFAULT) @@ -726,9 +731,12 @@ int rxe_requester(void *arg) else wqe->status =3D IB_WC_LOC_QP_OP_ERR; kfree_skb(skb); - goto err; + goto err_drop_ah; } =20 + if (ah) + rxe_drop_ref(ah); + /* * To prevent a race on wqe access between requester and completer, * wqe members state and psn need to be set before calling @@ -757,6 +765,9 @@ int rxe_requester(void *arg) =20 goto next_wqe; =20 +err_drop_ah: + if (ah) + rxe_drop_ref(ah); err: wqe->state =3D wqe_state_error; __rxe_do_task(&qp->comp.task); diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/r= xe/rxe_resp.c index e8f435fa6e4d..192cb9a096a1 100644 --- a/drivers/infiniband/sw/rxe/rxe_resp.c +++ b/drivers/infiniband/sw/rxe/rxe_resp.c @@ -632,7 +632,7 @@ static struct sk_buff *prepare_ack_packet(struct rxe_qp= *qp, if (ack->mask & RXE_ATMACK_MASK) atmack_set_orig(ack, qp->resp.atomic_orig); =20 - err =3D rxe_prepare(ack, skb); + err =3D rxe_prepare(&qp->pri_av, ack, skb); if (err) { kfree_skb(skb); return NULL; @@ -814,6 +814,10 @@ static enum resp_states execute(struct rxe_qp *qp, str= uct rxe_pkt_info *pkt) return RESPST_ERR_INVALIDATE_RKEY; } =20 + if (pkt->mask & RXE_END_MASK) + /* We successfully processed this new request. */ + qp->resp.msn++; + /* next expected psn, read handles this separately */ qp->resp.psn =3D (pkt->psn + 1) & BTH_PSN_MASK; qp->resp.ack_psn =3D qp->resp.psn; @@ -821,11 +825,9 @@ static enum resp_states execute(struct rxe_qp *qp, str= uct rxe_pkt_info *pkt) qp->resp.opcode =3D pkt->opcode; qp->resp.status =3D IB_WC_SUCCESS; =20 - if (pkt->mask & RXE_COMP_MASK) { - /* We successfully processed this new request. */ - qp->resp.msn++; + if (pkt->mask & RXE_COMP_MASK) return RESPST_COMPLETE; - } else if (qp_type(qp) =3D=3D IB_QPT_RC) + else if (qp_type(qp) =3D=3D IB_QPT_RC) return RESPST_ACKNOWLEDGE; else return RESPST_CLEANUP; diff --git a/drivers/input/input.c b/drivers/input/input.c index c3139bc2aa0d..ccaeb2426385 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -2285,12 +2285,6 @@ int input_register_device(struct input_dev *dev) /* KEY_RESERVED is not supposed to be transmitted to userspace. */ __clear_bit(KEY_RESERVED, dev->keybit); =20 - /* Buttonpads should not map BTN_RIGHT and/or BTN_MIDDLE. */ - if (test_bit(INPUT_PROP_BUTTONPAD, dev->propbit)) { - __clear_bit(BTN_RIGHT, dev->keybit); - __clear_bit(BTN_MIDDLE, dev->keybit); - } - /* Make sure that bitmasks not mentioned in dev->evbit are clean. */ input_cleanse_bitmasks(dev); =20 diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscree= n/zinitix.c index 1e70b8d2a8d7..400957f4c8c9 100644 --- a/drivers/input/touchscreen/zinitix.c +++ b/drivers/input/touchscreen/zinitix.c @@ -135,7 +135,7 @@ struct point_coord { =20 struct touch_event { __le16 status; - u8 finger_cnt; + u8 finger_mask; u8 time_stamp; struct point_coord point_coord[MAX_SUPPORTED_FINGER_NUM]; }; @@ -311,11 +311,32 @@ static int zinitix_send_power_on_sequence(struct bt54= 1_ts_data *bt541) static void zinitix_report_finger(struct bt541_ts_data *bt541, int slot, const struct point_coord *p) { + u16 x, y; + + if (unlikely(!(p->sub_status & + (SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE)))) { + dev_dbg(&bt541->client->dev, "unknown finger event %#02x\n", + p->sub_status); + return; + } + + x =3D le16_to_cpu(p->x); + y =3D le16_to_cpu(p->y); + input_mt_slot(bt541->input_dev, slot); - input_mt_report_slot_state(bt541->input_dev, MT_TOOL_FINGER, true); - touchscreen_report_pos(bt541->input_dev, &bt541->prop, - le16_to_cpu(p->x), le16_to_cpu(p->y), true); - input_report_abs(bt541->input_dev, ABS_MT_TOUCH_MAJOR, p->width); + if (input_mt_report_slot_state(bt541->input_dev, MT_TOOL_FINGER, + !(p->sub_status & SUB_BIT_UP))) { + touchscreen_report_pos(bt541->input_dev, + &bt541->prop, x, y, true); + input_report_abs(bt541->input_dev, + ABS_MT_TOUCH_MAJOR, p->width); + dev_dbg(&bt541->client->dev, "finger %d %s (%u, %u)\n", + slot, p->sub_status & SUB_BIT_DOWN ? "down" : "move", + x, y); + } else { + dev_dbg(&bt541->client->dev, "finger %d up (%u, %u)\n", + slot, x, y); + } } =20 static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler) @@ -323,6 +344,7 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void= *bt541_handler) struct bt541_ts_data *bt541 =3D bt541_handler; struct i2c_client *client =3D bt541->client; struct touch_event touch_event; + unsigned long finger_mask; int error; int i; =20 @@ -335,10 +357,14 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, vo= id *bt541_handler) goto out; } =20 - for (i =3D 0; i < MAX_SUPPORTED_FINGER_NUM; i++) - if (touch_event.point_coord[i].sub_status & SUB_BIT_EXIST) - zinitix_report_finger(bt541, i, - &touch_event.point_coord[i]); + finger_mask =3D touch_event.finger_mask; + for_each_set_bit(i, &finger_mask, MAX_SUPPORTED_FINGER_NUM) { + const struct point_coord *p =3D &touch_event.point_coord[i]; + + /* Only process contacts that are actually reported */ + if (p->sub_status & SUB_BIT_EXIST) + zinitix_report_finger(bt541, i, p); + } =20 input_mt_sync_frame(bt541->input_dev); input_sync(bt541->input_dev); diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c index 920fcc27c9a1..cae5a73ff518 100644 --- a/drivers/iommu/iova.c +++ b/drivers/iommu/iova.c @@ -154,10 +154,11 @@ __cached_rbnode_delete_update(struct iova_domain *iov= ad, struct iova *free) cached_iova =3D to_iova(iovad->cached32_node); if (free =3D=3D cached_iova || (free->pfn_hi < iovad->dma_32bit_pfn && - free->pfn_lo >=3D cached_iova->pfn_lo)) { + free->pfn_lo >=3D cached_iova->pfn_lo)) iovad->cached32_node =3D rb_next(&free->node); + + if (free->pfn_lo < iovad->dma_32bit_pfn) iovad->max32_alloc_size =3D iovad->dma_32bit_pfn; - } =20 cached_iova =3D to_iova(iovad->cached_node); if (free->pfn_lo >=3D cached_iova->pfn_lo) diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index ca752bdc710f..61bd9a3004ed 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -1006,7 +1006,9 @@ static int ipmmu_probe(struct platform_device *pdev) bitmap_zero(mmu->ctx, IPMMU_CTX_MAX); mmu->features =3D of_device_get_match_data(&pdev->dev); memset(mmu->utlb_ctx, IPMMU_CTX_INVALID, mmu->features->num_utlbs); - dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); + ret =3D dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); + if (ret) + return ret; =20 /* Map I/O memory and request IRQ. */ res =3D platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index 25b834104790..5971a1168666 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -562,22 +562,52 @@ static struct iommu_device *mtk_iommu_probe_device(st= ruct device *dev) { struct iommu_fwspec *fwspec =3D dev_iommu_fwspec_get(dev); struct mtk_iommu_data *data; + struct device_link *link; + struct device *larbdev; + unsigned int larbid, larbidx, i; =20 if (!fwspec || fwspec->ops !=3D &mtk_iommu_ops) return ERR_PTR(-ENODEV); /* Not a iommu client device */ =20 data =3D dev_iommu_priv_get(dev); =20 + /* + * Link the consumer device with the smi-larb device(supplier). + * The device that connects with each a larb is a independent HW. + * All the ports in each a device should be in the same larbs. + */ + larbid =3D MTK_M4U_TO_LARB(fwspec->ids[0]); + for (i =3D 1; i < fwspec->num_ids; i++) { + larbidx =3D MTK_M4U_TO_LARB(fwspec->ids[i]); + if (larbid !=3D larbidx) { + dev_err(dev, "Can only use one larb. Fail@larb%d-%d.\n", + larbid, larbidx); + return ERR_PTR(-EINVAL); + } + } + larbdev =3D data->larb_imu[larbid].dev; + link =3D device_link_add(dev, larbdev, + DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS); + if (!link) + dev_err(dev, "Unable to link %s\n", dev_name(larbdev)); return &data->iommu; } =20 static void mtk_iommu_release_device(struct device *dev) { struct iommu_fwspec *fwspec =3D dev_iommu_fwspec_get(dev); + struct mtk_iommu_data *data; + struct device *larbdev; + unsigned int larbid; =20 if (!fwspec || fwspec->ops !=3D &mtk_iommu_ops) return; =20 + data =3D dev_iommu_priv_get(dev); + larbid =3D MTK_M4U_TO_LARB(fwspec->ids[0]); + larbdev =3D data->larb_imu[larbid].dev; + device_link_remove(dev, larbdev); + iommu_fwspec_free(dev); } =20 @@ -848,7 +878,7 @@ static int mtk_iommu_probe(struct platform_device *pdev) plarbdev =3D of_find_device_by_node(larbnode); if (!plarbdev) { of_node_put(larbnode); - return -EPROBE_DEFER; + return -ENODEV; } data->larb_imu[id].dev =3D &plarbdev->dev; =20 diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c index be22fcf988ce..bc7ee90b9373 100644 --- a/drivers/iommu/mtk_iommu_v1.c +++ b/drivers/iommu/mtk_iommu_v1.c @@ -423,7 +423,18 @@ static struct iommu_device *mtk_iommu_probe_device(str= uct device *dev) struct iommu_fwspec *fwspec =3D dev_iommu_fwspec_get(dev); struct of_phandle_args iommu_spec; struct mtk_iommu_data *data; - int err, idx =3D 0; + int err, idx =3D 0, larbid, larbidx; + struct device_link *link; + struct device *larbdev; + + /* + * In the deferred case, free the existed fwspec. + * Always initialize the fwspec internally. + */ + if (fwspec) { + iommu_fwspec_free(dev); + fwspec =3D dev_iommu_fwspec_get(dev); + } =20 while (!of_parse_phandle_with_args(dev->of_node, "iommus", "#iommu-cells", @@ -444,6 +455,23 @@ static struct iommu_device *mtk_iommu_probe_device(str= uct device *dev) =20 data =3D dev_iommu_priv_get(dev); =20 + /* Link the consumer device with the smi-larb device(supplier) */ + larbid =3D mt2701_m4u_to_larb(fwspec->ids[0]); + for (idx =3D 1; idx < fwspec->num_ids; idx++) { + larbidx =3D mt2701_m4u_to_larb(fwspec->ids[idx]); + if (larbid !=3D larbidx) { + dev_err(dev, "Can only use one larb. Fail@larb%d-%d.\n", + larbid, larbidx); + return ERR_PTR(-EINVAL); + } + } + + larbdev =3D data->larb_imu[larbid].dev; + link =3D device_link_add(dev, larbdev, + DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS); + if (!link) + dev_err(dev, "Unable to link %s\n", dev_name(larbdev)); + return &data->iommu; } =20 @@ -464,10 +492,18 @@ static void mtk_iommu_probe_finalize(struct device *d= ev) static void mtk_iommu_release_device(struct device *dev) { struct iommu_fwspec *fwspec =3D dev_iommu_fwspec_get(dev); + struct mtk_iommu_data *data; + struct device *larbdev; + unsigned int larbid; =20 if (!fwspec || fwspec->ops !=3D &mtk_iommu_ops) return; =20 + data =3D dev_iommu_priv_get(dev); + larbid =3D mt2701_m4u_to_larb(fwspec->ids[0]); + larbdev =3D data->larb_imu[larbid].dev; + device_link_remove(dev, larbdev); + iommu_fwspec_free(dev); } =20 @@ -595,7 +631,7 @@ static int mtk_iommu_probe(struct platform_device *pdev) plarbdev =3D of_find_device_by_node(larbnode); if (!plarbdev) { of_node_put(larbnode); - return -EPROBE_DEFER; + return -ENODEV; } data->larb_imu[i].dev =3D &plarbdev->dev; =20 diff --git a/drivers/irqchip/irq-nvic.c b/drivers/irqchip/irq-nvic.c index ba4759b3e269..94230306e0ee 100644 --- a/drivers/irqchip/irq-nvic.c +++ b/drivers/irqchip/irq-nvic.c @@ -107,6 +107,7 @@ static int __init nvic_of_init(struct device_node *node, =20 if (!nvic_irq_domain) { pr_warn("Failed to allocate irq domain\n"); + iounmap(nvic_base); return -ENOMEM; } =20 @@ -116,6 +117,7 @@ static int __init nvic_of_init(struct device_node *node, if (ret) { pr_warn("Failed to allocate irq chips\n"); irq_domain_remove(nvic_irq_domain); + iounmap(nvic_base); return ret; } =20 diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c index 173e6520e06e..c0b457f26ec4 100644 --- a/drivers/irqchip/qcom-pdc.c +++ b/drivers/irqchip/qcom-pdc.c @@ -56,17 +56,18 @@ static u32 pdc_reg_read(int reg, u32 i) static void pdc_enable_intr(struct irq_data *d, bool on) { int pin_out =3D d->hwirq; + unsigned long flags; u32 index, mask; u32 enable; =20 index =3D pin_out / 32; mask =3D pin_out % 32; =20 - raw_spin_lock(&pdc_lock); + raw_spin_lock_irqsave(&pdc_lock, flags); enable =3D pdc_reg_read(IRQ_ENABLE_BANK, index); enable =3D on ? ENABLE_INTR(enable, mask) : CLEAR_INTR(enable, mask); pdc_reg_write(IRQ_ENABLE_BANK, index, enable); - raw_spin_unlock(&pdc_lock); + raw_spin_unlock_irqrestore(&pdc_lock, flags); } =20 static void qcom_pdc_gic_disable(struct irq_data *d) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index 544de2db6453..a0c252415c86 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -14,6 +14,7 @@ #include #include #include +#include #include =20 #define IMX_MU_CHANS 16 @@ -76,6 +77,7 @@ struct imx_mu_priv { const struct imx_mu_dcfg *dcfg; struct clk *clk; int irq; + bool suspend; =20 u32 xcr[4]; =20 @@ -334,6 +336,9 @@ static irqreturn_t imx_mu_isr(int irq, void *p) return IRQ_NONE; } =20 + if (priv->suspend) + pm_system_wakeup(); + return IRQ_HANDLED; } =20 @@ -702,6 +707,8 @@ static int __maybe_unused imx_mu_suspend_noirq(struct d= evice *dev) priv->xcr[i] =3D imx_mu_read(priv, priv->dcfg->xCR[i]); } =20 + priv->suspend =3D true; + return 0; } =20 @@ -718,11 +725,13 @@ static int __maybe_unused imx_mu_resume_noirq(struct = device *dev) * send failed, may lead to system freeze. This issue * is observed by testing freeze mode suspend. */ - if (!imx_mu_read(priv, priv->dcfg->xCR[0]) && !priv->clk) { + if (!priv->clk && !imx_mu_read(priv, priv->dcfg->xCR[0])) { for (i =3D 0; i < IMX_MU_xCR_MAX; i++) imx_mu_write(priv, priv->xcr[i], priv->dcfg->xCR[i]); } =20 + priv->suspend =3D false; + return 0; } =20 diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c index acd0675da681..78f7265039c6 100644 --- a/drivers/mailbox/tegra-hsp.c +++ b/drivers/mailbox/tegra-hsp.c @@ -412,6 +412,11 @@ static int tegra_hsp_mailbox_flush(struct mbox_chan *c= han, value =3D tegra_hsp_channel_readl(ch, HSP_SM_SHRD_MBOX); if ((value & HSP_SM_SHRD_MBOX_FULL) =3D=3D 0) { mbox_chan_txdone(chan, 0); + + /* Wait until channel is empty */ + if (chan->active_req !=3D NULL) + continue; + return 0; } =20 diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index 88c573eeb598..ad9f16689419 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -2060,9 +2060,11 @@ int bch_btree_check(struct cache_set *c) } } =20 + /* + * Must wait for all threads to stop. + */ wait_event_interruptible(check_state->wait, - atomic_read(&check_state->started) =3D=3D 0 || - test_bit(CACHE_SET_IO_DISABLE, &c->flags)); + atomic_read(&check_state->started) =3D=3D 0); =20 for (i =3D 0; i < check_state->total_threads; i++) { if (check_state->infos[i].result) { diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c index c7560f66dca8..68d3dd6b4f11 100644 --- a/drivers/md/bcache/writeback.c +++ b/drivers/md/bcache/writeback.c @@ -998,9 +998,11 @@ void bch_sectors_dirty_init(struct bcache_device *d) } } =20 + /* + * Must wait for all threads to stop. + */ wait_event_interruptible(state->wait, - atomic_read(&state->started) =3D=3D 0 || - test_bit(CACHE_SET_IO_DISABLE, &c->flags)); + atomic_read(&state->started) =3D=3D 0); =20 out: kfree(state); diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h index b855fef4f38a..adb9604e85ac 100644 --- a/drivers/md/dm-core.h +++ b/drivers/md/dm-core.h @@ -65,6 +65,8 @@ struct mapped_device { struct gendisk *disk; struct dax_device *dax_dev; =20 + unsigned long __percpu *pending_io; + /* * A list of ios that arrived while we were suspended. */ diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index d4ae31558826..f51aea71cb03 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -2590,7 +2590,7 @@ static int crypt_set_keyring_key(struct crypt_config = *cc, const char *key_string =20 static int get_key_size(char **key_string) { - return (*key_string[0] =3D=3D ':') ? -EINVAL : strlen(*key_string) >> 1; + return (*key_string[0] =3D=3D ':') ? -EINVAL : (int)(strlen(*key_string) = >> 1); } =20 #endif /* CONFIG_KEYS */ diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index 7af242de3202..5025c7f048ed 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -2471,9 +2471,11 @@ static void do_journal_write(struct dm_integrity_c *= ic, unsigned write_start, dm_integrity_io_error(ic, "invalid sector in journal", -EIO); sec &=3D ~(sector_t)(ic->sectors_per_block - 1); } + if (unlikely(sec >=3D ic->provided_data_sectors)) { + journal_entry_set_unused(je); + continue; + } } - if (unlikely(sec >=3D ic->provided_data_sectors)) - continue; get_area_and_offset(ic, sec, &area, &offset); restore_last_bytes(ic, access_journal_data(ic, i, j), je); for (k =3D j + 1; k < ic->journal_section_entries; k++) { diff --git a/drivers/md/dm-stats.c b/drivers/md/dm-stats.c index 35d368c418d0..0e039a8c0bf2 100644 --- a/drivers/md/dm-stats.c +++ b/drivers/md/dm-stats.c @@ -195,6 +195,7 @@ void dm_stats_init(struct dm_stats *stats) =20 mutex_init(&stats->mutex); INIT_LIST_HEAD(&stats->list); + stats->precise_timestamps =3D false; stats->last =3D alloc_percpu(struct dm_stats_last_position); for_each_possible_cpu(cpu) { last =3D per_cpu_ptr(stats->last, cpu); @@ -231,6 +232,22 @@ void dm_stats_cleanup(struct dm_stats *stats) mutex_destroy(&stats->mutex); } =20 +static void dm_stats_recalc_precise_timestamps(struct dm_stats *stats) +{ + struct list_head *l; + struct dm_stat *tmp_s; + bool precise_timestamps =3D false; + + list_for_each(l, &stats->list) { + tmp_s =3D container_of(l, struct dm_stat, list_entry); + if (tmp_s->stat_flags & STAT_PRECISE_TIMESTAMPS) { + precise_timestamps =3D true; + break; + } + } + stats->precise_timestamps =3D precise_timestamps; +} + static int dm_stats_create(struct dm_stats *stats, sector_t start, sector_= t end, sector_t step, unsigned stat_flags, unsigned n_histogram_entries, @@ -376,6 +393,9 @@ static int dm_stats_create(struct dm_stats *stats, sect= or_t start, sector_t end, } ret_id =3D s->id; list_add_tail_rcu(&s->list_entry, l); + + dm_stats_recalc_precise_timestamps(stats); + mutex_unlock(&stats->mutex); =20 resume_callback(md); @@ -418,6 +438,9 @@ static int dm_stats_delete(struct dm_stats *stats, int = id) } =20 list_del_rcu(&s->list_entry); + + dm_stats_recalc_precise_timestamps(stats); + mutex_unlock(&stats->mutex); =20 /* @@ -621,13 +644,14 @@ static void __dm_stat_bio(struct dm_stat *s, int bi_r= w, =20 void dm_stats_account_io(struct dm_stats *stats, unsigned long bi_rw, sector_t bi_sector, unsigned bi_sectors, bool end, - unsigned long duration_jiffies, + unsigned long start_time, struct dm_stats_aux *stats_aux) { struct dm_stat *s; sector_t end_sector; struct dm_stats_last_position *last; bool got_precise_time; + unsigned long duration_jiffies =3D 0; =20 if (unlikely(!bi_sectors)) return; @@ -647,16 +671,16 @@ void dm_stats_account_io(struct dm_stats *stats, unsi= gned long bi_rw, )); WRITE_ONCE(last->last_sector, end_sector); WRITE_ONCE(last->last_rw, bi_rw); - } + } else + duration_jiffies =3D jiffies - start_time; =20 rcu_read_lock(); =20 got_precise_time =3D false; list_for_each_entry_rcu(s, &stats->list, list_entry) { if (s->stat_flags & STAT_PRECISE_TIMESTAMPS && !got_precise_time) { - if (!end) - stats_aux->duration_ns =3D ktime_to_ns(ktime_get()); - else + /* start (!end) duration_ns is set by DM core's alloc_io() */ + if (end) stats_aux->duration_ns =3D ktime_to_ns(ktime_get()) - stats_aux->durat= ion_ns; got_precise_time =3D true; } diff --git a/drivers/md/dm-stats.h b/drivers/md/dm-stats.h index 2ddfae678f32..09c81a1ec057 100644 --- a/drivers/md/dm-stats.h +++ b/drivers/md/dm-stats.h @@ -13,8 +13,7 @@ struct dm_stats { struct mutex mutex; struct list_head list; /* list of struct dm_stat */ struct dm_stats_last_position __percpu *last; - sector_t last_sector; - unsigned last_rw; + bool precise_timestamps; }; =20 struct dm_stats_aux { @@ -32,7 +31,7 @@ int dm_stats_message(struct mapped_device *md, unsigned a= rgc, char **argv, =20 void dm_stats_account_io(struct dm_stats *stats, unsigned long bi_rw, sector_t bi_sector, unsigned bi_sectors, bool end, - unsigned long duration_jiffies, + unsigned long start_time, struct dm_stats_aux *aux); =20 static inline bool dm_stats_used(struct dm_stats *st) @@ -40,4 +39,10 @@ static inline bool dm_stats_used(struct dm_stats *st) return !list_empty(&st->list); } =20 +static inline void dm_stats_record_start(struct dm_stats *stats, struct dm= _stats_aux *aux) +{ + if (unlikely(stats->precise_timestamps)) + aux->duration_ns =3D ktime_to_ns(ktime_get()); +} + #endif diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 356a0183e1ad..5fd3660e07b5 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -484,33 +484,48 @@ u64 dm_start_time_ns_from_clone(struct bio *bio) } EXPORT_SYMBOL_GPL(dm_start_time_ns_from_clone); =20 -static void start_io_acct(struct dm_io *io) +static bool bio_is_flush_with_data(struct bio *bio) { - struct mapped_device *md =3D io->md; - struct bio *bio =3D io->orig_bio; - - bio_start_io_acct_time(bio, io->start_time); - if (unlikely(dm_stats_used(&md->stats))) - dm_stats_account_io(&md->stats, bio_data_dir(bio), - bio->bi_iter.bi_sector, bio_sectors(bio), - false, 0, &io->stats_aux); + return ((bio->bi_opf & REQ_PREFLUSH) && bio->bi_iter.bi_size); } =20 -static void end_io_acct(struct mapped_device *md, struct bio *bio, - unsigned long start_time, struct dm_stats_aux *stats_aux) +static void dm_io_acct(bool end, struct mapped_device *md, struct bio *bio, + unsigned long start_time, struct dm_stats_aux *stats_aux) { - unsigned long duration =3D jiffies - start_time; + bool is_flush_with_data; + unsigned int bi_size; =20 - bio_end_io_acct(bio, start_time); + /* If REQ_PREFLUSH set save any payload but do not account it */ + is_flush_with_data =3D bio_is_flush_with_data(bio); + if (is_flush_with_data) { + bi_size =3D bio->bi_iter.bi_size; + bio->bi_iter.bi_size =3D 0; + } + + if (!end) + bio_start_io_acct_time(bio, start_time); + else + bio_end_io_acct(bio, start_time); =20 if (unlikely(dm_stats_used(&md->stats))) dm_stats_account_io(&md->stats, bio_data_dir(bio), bio->bi_iter.bi_sector, bio_sectors(bio), - true, duration, stats_aux); + end, start_time, stats_aux); + + /* Restore bio's payload so it does get accounted upon requeue */ + if (is_flush_with_data) + bio->bi_iter.bi_size =3D bi_size; +} + +static void start_io_acct(struct dm_io *io) +{ + dm_io_acct(false, io->md, io->orig_bio, io->start_time, &io->stats_aux); +} =20 - /* nudge anyone waiting on suspend queue */ - if (unlikely(wq_has_sleeper(&md->wait))) - wake_up(&md->wait); +static void end_io_acct(struct mapped_device *md, struct bio *bio, + unsigned long start_time, struct dm_stats_aux *stats_aux) +{ + dm_io_acct(true, md, bio, start_time, stats_aux); } =20 static struct dm_io *alloc_io(struct mapped_device *md, struct bio *bio) @@ -531,12 +546,15 @@ static struct dm_io *alloc_io(struct mapped_device *m= d, struct bio *bio) io->magic =3D DM_IO_MAGIC; io->status =3D 0; atomic_set(&io->io_count, 1); + this_cpu_inc(*md->pending_io); io->orig_bio =3D bio; io->md =3D md; spin_lock_init(&io->endio_lock); =20 io->start_time =3D jiffies; =20 + dm_stats_record_start(&md->stats, &io->stats_aux); + return io; } =20 @@ -826,11 +844,17 @@ void dm_io_dec_pending(struct dm_io *io, blk_status_t= error) stats_aux =3D io->stats_aux; free_io(md, io); end_io_acct(md, bio, start_time, &stats_aux); + smp_wmb(); + this_cpu_dec(*md->pending_io); + + /* nudge anyone waiting on suspend queue */ + if (unlikely(wq_has_sleeper(&md->wait))) + wake_up(&md->wait); =20 if (io_error =3D=3D BLK_STS_DM_REQUEUE) return; =20 - if ((bio->bi_opf & REQ_PREFLUSH) && bio->bi_iter.bi_size) { + if (bio_is_flush_with_data(bio)) { /* * Preflush done for flush with data, reissue * without REQ_PREFLUSH. @@ -1674,6 +1698,7 @@ static void cleanup_mapped_device(struct mapped_devic= e *md) md->dax_dev =3D NULL; } =20 + dm_cleanup_zoned_dev(md); if (md->disk) { spin_lock(&_minor_lock); md->disk->private_data =3D NULL; @@ -1686,6 +1711,11 @@ static void cleanup_mapped_device(struct mapped_devi= ce *md) blk_cleanup_disk(md->disk); } =20 + if (md->pending_io) { + free_percpu(md->pending_io); + md->pending_io =3D NULL; + } + cleanup_srcu_struct(&md->io_barrier); =20 mutex_destroy(&md->suspend_lock); @@ -1694,7 +1724,6 @@ static void cleanup_mapped_device(struct mapped_devic= e *md) mutex_destroy(&md->swap_bios_lock); =20 dm_mq_cleanup_mapped_device(md); - dm_cleanup_zoned_dev(md); } =20 /* @@ -1784,6 +1813,10 @@ static struct mapped_device *alloc_dev(int minor) if (!md->wq) goto bad; =20 + md->pending_io =3D alloc_percpu(unsigned long); + if (!md->pending_io) + goto bad; + dm_stats_init(&md->stats); =20 /* Populate the mapping, nobody knows we exist yet */ @@ -2191,16 +2224,13 @@ void dm_put(struct mapped_device *md) } EXPORT_SYMBOL_GPL(dm_put); =20 -static bool md_in_flight_bios(struct mapped_device *md) +static bool dm_in_flight_bios(struct mapped_device *md) { int cpu; - struct block_device *part =3D dm_disk(md)->part0; - long sum =3D 0; + unsigned long sum =3D 0; =20 - for_each_possible_cpu(cpu) { - sum +=3D part_stat_local_read_cpu(part, in_flight[0], cpu); - sum +=3D part_stat_local_read_cpu(part, in_flight[1], cpu); - } + for_each_possible_cpu(cpu) + sum +=3D *per_cpu_ptr(md->pending_io, cpu); =20 return sum !=3D 0; } @@ -2213,7 +2243,7 @@ static int dm_wait_for_bios_completion(struct mapped_= device *md, unsigned int ta while (true) { prepare_to_wait(&md->wait, &wait, task_state); =20 - if (!md_in_flight_bios(md)) + if (!dm_in_flight_bios(md)) break; =20 if (signal_pending_state(task_state, current)) { @@ -2225,6 +2255,8 @@ static int dm_wait_for_bios_completion(struct mapped_= device *md, unsigned int ta } finish_wait(&md->wait, &wait); =20 + smp_rmb(); + return r; } =20 diff --git a/drivers/media/i2c/adv7511-v4l2.c b/drivers/media/i2c/adv7511-v= 4l2.c index 41f4e749a859..2217004264e4 100644 --- a/drivers/media/i2c/adv7511-v4l2.c +++ b/drivers/media/i2c/adv7511-v4l2.c @@ -544,7 +544,7 @@ static void log_infoframe(struct v4l2_subdev *sd, const= struct adv7511_cfg_read_ buffer[3] =3D 0; buffer[3] =3D hdmi_infoframe_checksum(buffer, len + 4); =20 - if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) { + if (hdmi_infoframe_unpack(&frame, buffer, len + 4) < 0) { v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc); return; } diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 44768b59a6ff..0ce323836dad 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -2484,7 +2484,7 @@ static int adv76xx_read_infoframe(struct v4l2_subdev = *sd, int index, buffer[i + 3] =3D infoframe_read(sd, adv76xx_cri[index].payload_addr + i); =20 - if (hdmi_infoframe_unpack(frame, buffer, sizeof(buffer)) < 0) { + if (hdmi_infoframe_unpack(frame, buffer, len + 3) < 0) { v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, adv76xx_cri[index].desc); return -ENOENT; diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 7f8acbdf0db4..8ab4c63839b4 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -2593,7 +2593,7 @@ static void log_infoframe(struct v4l2_subdev *sd, con= st struct adv7842_cfg_read_ for (i =3D 0; i < len; i++) buffer[i + 3] =3D infoframe_read(sd, cri->payload_addr + i); =20 - if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) { + if (hdmi_infoframe_unpack(&frame, buffer, len + 3) < 0) { v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc); return; } diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index ddbd71394db3..db5a19babe67 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -2293,7 +2293,6 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd, struct ov5640_dev *sensor =3D to_ov5640_dev(sd); const struct ov5640_mode_info *new_mode; struct v4l2_mbus_framefmt *mbus_fmt =3D &format->format; - struct v4l2_mbus_framefmt *fmt; int ret; =20 if (format->pad !=3D 0) @@ -2311,12 +2310,10 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd, if (ret) goto out; =20 - if (format->which =3D=3D V4L2_SUBDEV_FORMAT_TRY) - fmt =3D v4l2_subdev_get_try_format(sd, sd_state, 0); - else - fmt =3D &sensor->fmt; - - *fmt =3D *mbus_fmt; + if (format->which =3D=3D V4L2_SUBDEV_FORMAT_TRY) { + *v4l2_subdev_get_try_format(sd, sd_state, 0) =3D *mbus_fmt; + goto out; + } =20 if (new_mode !=3D sensor->current_mode) { sensor->current_mode =3D new_mode; @@ -2325,6 +2322,9 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd, if (mbus_fmt->code !=3D sensor->fmt.code) sensor->pending_fmt_change =3D true; =20 + /* update format even if code is unchanged, resolution might change */ + sensor->fmt =3D *mbus_fmt; + __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, ov5640_calc_pixel_rate(sensor)); out: diff --git a/drivers/media/i2c/ov5648.c b/drivers/media/i2c/ov5648.c index 947d437ed0ef..ef8b52dc9401 100644 --- a/drivers/media/i2c/ov5648.c +++ b/drivers/media/i2c/ov5648.c @@ -639,7 +639,7 @@ struct ov5648_ctrls { struct v4l2_ctrl *pixel_rate; =20 struct v4l2_ctrl_handler handler; -} __packed; +}; =20 struct ov5648_sensor { struct device *dev; @@ -1778,8 +1778,14 @@ static int ov5648_state_configure(struct ov5648_sens= or *sensor, =20 static int ov5648_state_init(struct ov5648_sensor *sensor) { - return ov5648_state_configure(sensor, &ov5648_modes[0], - ov5648_mbus_codes[0]); + int ret; + + mutex_lock(&sensor->mutex); + ret =3D ov5648_state_configure(sensor, &ov5648_modes[0], + ov5648_mbus_codes[0]); + mutex_unlock(&sensor->mutex); + + return ret; } =20 /* Sensor Base */ diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c index f67412150b16..eb59dc8bb592 100644 --- a/drivers/media/i2c/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -472,9 +472,16 @@ static int ov6650_get_selection(struct v4l2_subdev *sd, { struct i2c_client *client =3D v4l2_get_subdevdata(sd); struct ov6650 *priv =3D to_ov6650(client); + struct v4l2_rect *rect; =20 - if (sel->which !=3D V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; + if (sel->which =3D=3D V4L2_SUBDEV_FORMAT_TRY) { + /* pre-select try crop rectangle */ + rect =3D &sd_state->pads->try_crop; + + } else { + /* pre-select active crop rectangle */ + rect =3D &priv->rect; + } =20 switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: @@ -483,14 +490,33 @@ static int ov6650_get_selection(struct v4l2_subdev *s= d, sel->r.width =3D W_CIF; sel->r.height =3D H_CIF; return 0; + case V4L2_SEL_TGT_CROP: - sel->r =3D priv->rect; + /* use selected crop rectangle */ + sel->r =3D *rect; return 0; + default: return -EINVAL; } } =20 +static bool is_unscaled_ok(int width, int height, struct v4l2_rect *rect) +{ + return width > rect->width >> 1 || height > rect->height >> 1; +} + +static void ov6650_bind_align_crop_rectangle(struct v4l2_rect *rect) +{ + v4l_bound_align_image(&rect->width, 2, W_CIF, 1, + &rect->height, 2, H_CIF, 1, 0); + v4l_bound_align_image(&rect->left, DEF_HSTRT << 1, + (DEF_HSTRT << 1) + W_CIF - (__s32)rect->width, 1, + &rect->top, DEF_VSTRT << 1, + (DEF_VSTRT << 1) + H_CIF - (__s32)rect->height, + 1, 0); +} + static int ov6650_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) @@ -499,18 +525,30 @@ static int ov6650_set_selection(struct v4l2_subdev *s= d, struct ov6650 *priv =3D to_ov6650(client); int ret; =20 - if (sel->which !=3D V4L2_SUBDEV_FORMAT_ACTIVE || - sel->target !=3D V4L2_SEL_TGT_CROP) + if (sel->target !=3D V4L2_SEL_TGT_CROP) return -EINVAL; =20 - v4l_bound_align_image(&sel->r.width, 2, W_CIF, 1, - &sel->r.height, 2, H_CIF, 1, 0); - v4l_bound_align_image(&sel->r.left, DEF_HSTRT << 1, - (DEF_HSTRT << 1) + W_CIF - (__s32)sel->r.width, 1, - &sel->r.top, DEF_VSTRT << 1, - (DEF_VSTRT << 1) + H_CIF - (__s32)sel->r.height, - 1, 0); + ov6650_bind_align_crop_rectangle(&sel->r); + + if (sel->which =3D=3D V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_rect *crop =3D &sd_state->pads->try_crop; + struct v4l2_mbus_framefmt *mf =3D &sd_state->pads->try_fmt; + /* detect current pad config scaling factor */ + bool half_scale =3D !is_unscaled_ok(mf->width, mf->height, crop); + + /* store new crop rectangle */ + *crop =3D sel->r; =20 + /* adjust frame size */ + mf->width =3D crop->width >> half_scale; + mf->height =3D crop->height >> half_scale; + + return 0; + } + + /* V4L2_SUBDEV_FORMAT_ACTIVE */ + + /* apply new crop rectangle */ ret =3D ov6650_reg_write(client, REG_HSTRT, sel->r.left >> 1); if (!ret) { priv->rect.width +=3D priv->rect.left - sel->r.left; @@ -562,30 +600,13 @@ static int ov6650_get_fmt(struct v4l2_subdev *sd, return 0; } =20 -static bool is_unscaled_ok(int width, int height, struct v4l2_rect *rect) -{ - return width > rect->width >> 1 || height > rect->height >> 1; -} - #define to_clkrc(div) ((div) - 1) =20 /* set the format we will capture in */ -static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt = *mf) +static int ov6650_s_fmt(struct v4l2_subdev *sd, u32 code, bool half_scale) { struct i2c_client *client =3D v4l2_get_subdevdata(sd); struct ov6650 *priv =3D to_ov6650(client); - bool half_scale =3D !is_unscaled_ok(mf->width, mf->height, &priv->rect); - struct v4l2_subdev_selection sel =3D { - .which =3D V4L2_SUBDEV_FORMAT_ACTIVE, - .target =3D V4L2_SEL_TGT_CROP, - .r.left =3D priv->rect.left + (priv->rect.width >> 1) - - (mf->width >> (1 - half_scale)), - .r.top =3D priv->rect.top + (priv->rect.height >> 1) - - (mf->height >> (1 - half_scale)), - .r.width =3D mf->width << half_scale, - .r.height =3D mf->height << half_scale, - }; - u32 code =3D mf->code; u8 coma_set =3D 0, coma_mask =3D 0, coml_set, coml_mask; int ret; =20 @@ -653,9 +674,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct = v4l2_mbus_framefmt *mf) coma_mask |=3D COMA_QCIF; } =20 - ret =3D ov6650_set_selection(sd, NULL, &sel); - if (!ret) - ret =3D ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask); + ret =3D ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask); if (!ret) { priv->half_scale =3D half_scale; =20 @@ -674,14 +693,12 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf =3D &format->format; struct i2c_client *client =3D v4l2_get_subdevdata(sd); struct ov6650 *priv =3D to_ov6650(client); + struct v4l2_rect *crop; + bool half_scale; =20 if (format->pad) return -EINVAL; =20 - if (is_unscaled_ok(mf->width, mf->height, &priv->rect)) - v4l_bound_align_image(&mf->width, 2, W_CIF, 1, - &mf->height, 2, H_CIF, 1, 0); - switch (mf->code) { case MEDIA_BUS_FMT_Y10_1X10: mf->code =3D MEDIA_BUS_FMT_Y8_1X8; @@ -699,10 +716,17 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd, break; } =20 + if (format->which =3D=3D V4L2_SUBDEV_FORMAT_TRY) + crop =3D &sd_state->pads->try_crop; + else + crop =3D &priv->rect; + + half_scale =3D !is_unscaled_ok(mf->width, mf->height, crop); + if (format->which =3D=3D V4L2_SUBDEV_FORMAT_TRY) { - /* store media bus format code and frame size in pad config */ - sd_state->pads->try_fmt.width =3D mf->width; - sd_state->pads->try_fmt.height =3D mf->height; + /* store new mbus frame format code and size in pad config */ + sd_state->pads->try_fmt.width =3D crop->width >> half_scale; + sd_state->pads->try_fmt.height =3D crop->height >> half_scale; sd_state->pads->try_fmt.code =3D mf->code; =20 /* return default mbus frame format updated with pad config */ @@ -712,9 +736,11 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd, mf->code =3D sd_state->pads->try_fmt.code; =20 } else { - /* apply new media bus format code and frame size */ - int ret =3D ov6650_s_fmt(sd, mf); + int ret =3D 0; =20 + /* apply new media bus frame format and scaling if changed */ + if (mf->code !=3D priv->code || half_scale !=3D priv->half_scale) + ret =3D ov6650_s_fmt(sd, mf->code, half_scale); if (ret) return ret; =20 @@ -890,9 +916,8 @@ static int ov6650_video_probe(struct v4l2_subdev *sd) if (!ret) ret =3D ov6650_prog_dflt(client, xclk->clkrc); if (!ret) { - struct v4l2_mbus_framefmt mf =3D ov6650_def_fmt; - - ret =3D ov6650_s_fmt(sd, &mf); + /* driver default frame format, no scaling */ + ret =3D ov6650_s_fmt(sd, ov6650_def_fmt.code, false); } if (!ret) ret =3D v4l2_ctrl_handler_setup(&priv->hdl); diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8x= x/bttv-driver.c index 0e9df8b35ac6..661ebfa7bf3f 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -3890,7 +3890,7 @@ static int bttv_register_video(struct bttv *btv) =20 /* video */ vdev_init(btv, &btv->video_dev, &bttv_video_template, "video"); - btv->video_dev.device_caps =3D V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | + btv->video_dev.device_caps =3D V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; if (btv->tuner_type !=3D TUNER_ABSENT) btv->video_dev.device_caps |=3D V4L2_CAP_TUNER; @@ -3911,7 +3911,7 @@ static int bttv_register_video(struct bttv *btv) /* vbi */ vdev_init(btv, &btv->vbi_dev, &bttv_video_template, "vbi"); btv->vbi_dev.device_caps =3D V4L2_CAP_VBI_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | V4L2_CAP_TUNER; + V4L2_CAP_STREAMING; if (btv->tuner_type !=3D TUNER_ABSENT) btv->vbi_dev.device_caps |=3D V4L2_CAP_TUNER; =20 diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx= 88-mpeg.c index 680e1e3fe89b..2c1d5137ac47 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -162,6 +162,9 @@ int cx8802_start_dma(struct cx8802_dev *dev, cx_write(MO_TS_GPCNTRL, GP_COUNT_CONTROL_RESET); q->count =3D 0; =20 + /* clear interrupt status register */ + cx_write(MO_TS_INTSTAT, 0x1f1111); + /* enable irqs */ dprintk(1, "setting the interrupt mask\n"); cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_TSINT); diff --git a/drivers/media/pci/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/= ivtv-driver.h index 4cf92dee6527..ce3a7ca51736 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.h +++ b/drivers/media/pci/ivtv/ivtv-driver.h @@ -330,7 +330,6 @@ struct ivtv_stream { struct ivtv *itv; /* for ease of use */ const char *name; /* name of the stream */ int type; /* stream type */ - u32 caps; /* V4L2 capabilities */ =20 struct v4l2_fh *fh; /* pointer to the streaming filehandle */ spinlock_t qlock; /* locks access to the queues */ diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/i= vtv-ioctl.c index 0cdf6b3210c2..fee460e2ca86 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -438,7 +438,7 @@ static int ivtv_g_fmt_vid_out_overlay(struct file *file= , void *fh, struct v4l2_f struct ivtv_stream *s =3D &itv->streams[fh2id(fh)->type]; struct v4l2_window *winfmt =3D &fmt->fmt.win; =20 - if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -EINVAL; if (!itv->osd_video_pbase) return -EINVAL; @@ -549,7 +549,7 @@ static int ivtv_try_fmt_vid_out_overlay(struct file *fi= le, void *fh, struct v4l2 u32 chromakey =3D fmt->fmt.win.chromakey; u8 global_alpha =3D fmt->fmt.win.global_alpha; =20 - if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -EINVAL; if (!itv->osd_video_pbase) return -EINVAL; @@ -1383,7 +1383,7 @@ static int ivtv_g_fbuf(struct file *file, void *fh, s= truct v4l2_framebuffer *fb) 0, }; =20 - if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -ENOTTY; if (!itv->osd_video_pbase) return -ENOTTY; @@ -1450,7 +1450,7 @@ static int ivtv_s_fbuf(struct file *file, void *fh, c= onst struct v4l2_framebuffe struct ivtv_stream *s =3D &itv->streams[fh2id(fh)->type]; struct yuv_playback_info *yi =3D &itv->yuv_info; =20 - if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -ENOTTY; if (!itv->osd_video_pbase) return -ENOTTY; @@ -1470,7 +1470,7 @@ static int ivtv_overlay(struct file *file, void *fh, = unsigned int on) struct ivtv *itv =3D id->itv; struct ivtv_stream *s =3D &itv->streams[fh2id(fh)->type]; =20 - if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -ENOTTY; if (!itv->osd_video_pbase) return -ENOTTY; diff --git a/drivers/media/pci/ivtv/ivtv-streams.c b/drivers/media/pci/ivtv= /ivtv-streams.c index 6e455948cc77..13d7d55e6594 100644 --- a/drivers/media/pci/ivtv/ivtv-streams.c +++ b/drivers/media/pci/ivtv/ivtv-streams.c @@ -176,7 +176,7 @@ static void ivtv_stream_init(struct ivtv *itv, int type) s->itv =3D itv; s->type =3D type; s->name =3D ivtv_stream_info[type].name; - s->caps =3D ivtv_stream_info[type].v4l2_caps; + s->vdev.device_caps =3D ivtv_stream_info[type].v4l2_caps; =20 if (ivtv_stream_info[type].pio) s->dma =3D DMA_NONE; @@ -299,12 +299,9 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) if (s_mpg->vdev.v4l2_dev) num =3D s_mpg->vdev.num + ivtv_stream_info[type].num_offset; } - s->vdev.device_caps =3D s->caps; - if (itv->osd_video_pbase) { - itv->streams[IVTV_DEC_STREAM_TYPE_YUV].vdev.device_caps |=3D - V4L2_CAP_VIDEO_OUTPUT_OVERLAY; - itv->streams[IVTV_DEC_STREAM_TYPE_MPG].vdev.device_caps |=3D - V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + if (itv->osd_video_pbase && (type =3D=3D IVTV_DEC_STREAM_TYPE_YUV || + type =3D=3D IVTV_DEC_STREAM_TYPE_MPG)) { + s->vdev.device_caps |=3D V4L2_CAP_VIDEO_OUTPUT_OVERLAY; itv->v4l2_cap |=3D V4L2_CAP_VIDEO_OUTPUT_OVERLAY; } video_set_drvdata(&s->vdev, s); diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/s= aa7134/saa7134-alsa.c index fb24d2ed3621..d3cde05a6eba 100644 --- a/drivers/media/pci/saa7134/saa7134-alsa.c +++ b/drivers/media/pci/saa7134/saa7134-alsa.c @@ -1214,7 +1214,7 @@ static int alsa_device_exit(struct saa7134_dev *dev) =20 static int saa7134_alsa_init(void) { - struct saa7134_dev *dev =3D NULL; + struct saa7134_dev *dev; =20 saa7134_dmasound_init =3D alsa_device_init; saa7134_dmasound_exit =3D alsa_device_exit; @@ -1229,7 +1229,7 @@ static int saa7134_alsa_init(void) alsa_device_init(dev); } =20 - if (dev =3D=3D NULL) + if (list_empty(&saa7134_devlist)) pr_info("saa7134 ALSA: no saa7134 cards found\n"); =20 return 0; diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform= /aspeed-video.c index 7a24daf7165a..bdeecde0d997 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -153,7 +153,7 @@ #define VE_SRC_TB_EDGE_DET_BOT GENMASK(28, VE_SRC_TB_EDGE_DET_BOT_SHF) =20 #define VE_MODE_DETECT_STATUS 0x098 -#define VE_MODE_DETECT_H_PIXELS GENMASK(11, 0) +#define VE_MODE_DETECT_H_PERIOD GENMASK(11, 0) #define VE_MODE_DETECT_V_LINES_SHF 16 #define VE_MODE_DETECT_V_LINES GENMASK(27, VE_MODE_DETECT_V_LINES_SHF) #define VE_MODE_DETECT_STATUS_VSYNC BIT(28) @@ -164,6 +164,8 @@ #define VE_SYNC_STATUS_VSYNC_SHF 16 #define VE_SYNC_STATUS_VSYNC GENMASK(27, VE_SYNC_STATUS_VSYNC_SHF) =20 +#define VE_H_TOTAL_PIXELS 0x0A0 + #define VE_INTERRUPT_CTRL 0x304 #define VE_INTERRUPT_STATUS 0x308 #define VE_INTERRUPT_MODE_DETECT_WD BIT(0) @@ -802,6 +804,7 @@ static void aspeed_video_get_resolution(struct aspeed_v= ideo *video) u32 src_lr_edge; u32 src_tb_edge; u32 sync; + u32 htotal; struct v4l2_bt_timings *det =3D &video->detected_timings; =20 det->width =3D MIN_WIDTH; @@ -847,6 +850,7 @@ static void aspeed_video_get_resolution(struct aspeed_v= ideo *video) src_tb_edge =3D aspeed_video_read(video, VE_SRC_TB_EDGE_DET); mds =3D aspeed_video_read(video, VE_MODE_DETECT_STATUS); sync =3D aspeed_video_read(video, VE_SYNC_STATUS); + htotal =3D aspeed_video_read(video, VE_H_TOTAL_PIXELS); =20 video->frame_bottom =3D (src_tb_edge & VE_SRC_TB_EDGE_DET_BOT) >> VE_SRC_TB_EDGE_DET_BOT_SHF; @@ -863,8 +867,7 @@ static void aspeed_video_get_resolution(struct aspeed_v= ideo *video) VE_SRC_LR_EDGE_DET_RT_SHF; video->frame_left =3D src_lr_edge & VE_SRC_LR_EDGE_DET_LEFT; det->hfrontporch =3D video->frame_left; - det->hbackporch =3D (mds & VE_MODE_DETECT_H_PIXELS) - - video->frame_right; + det->hbackporch =3D htotal - video->frame_right; det->hsync =3D sync & VE_SYNC_STATUS_HSYNC; if (video->frame_left > video->frame_right) continue; diff --git a/drivers/media/platform/atmel/atmel-isc-base.c b/drivers/media/= platform/atmel/atmel-isc-base.c index 660cd0ab6749..24807782c9e5 100644 --- a/drivers/media/platform/atmel/atmel-isc-base.c +++ b/drivers/media/platform/atmel/atmel-isc-base.c @@ -1369,14 +1369,12 @@ static int isc_enum_framesizes(struct file *file, v= oid *fh, struct v4l2_frmsizeenum *fsize) { struct isc_device *isc =3D video_drvdata(file); - struct v4l2_subdev_frame_size_enum fse =3D { - .code =3D isc->config.sd_format->mbus_code, - .index =3D fsize->index, - .which =3D V4L2_SUBDEV_FORMAT_ACTIVE, - }; int ret =3D -EINVAL; int i; =20 + if (fsize->index) + return -EINVAL; + for (i =3D 0; i < isc->num_user_formats; i++) if (isc->user_formats[i]->fourcc =3D=3D fsize->pixel_format) ret =3D 0; @@ -1388,14 +1386,14 @@ static int isc_enum_framesizes(struct file *file, v= oid *fh, if (ret) return ret; =20 - ret =3D v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size, - NULL, &fse); - if (ret) - return ret; + fsize->type =3D V4L2_FRMSIZE_TYPE_CONTINUOUS; =20 - fsize->type =3D V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width =3D fse.max_width; - fsize->discrete.height =3D fse.max_height; + fsize->stepwise.min_width =3D 16; + fsize->stepwise.max_width =3D isc->max_width; + fsize->stepwise.min_height =3D 16; + fsize->stepwise.max_height =3D isc->max_height; + fsize->stepwise.step_width =3D 1; + fsize->stepwise.step_height =3D 1; =20 return 0; } diff --git a/drivers/media/platform/atmel/atmel-sama7g5-isc.c b/drivers/med= ia/platform/atmel/atmel-sama7g5-isc.c index 5d1c76f680f3..2b1082295c13 100644 --- a/drivers/media/platform/atmel/atmel-sama7g5-isc.c +++ b/drivers/media/platform/atmel/atmel-sama7g5-isc.c @@ -556,7 +556,6 @@ static int microchip_xisc_remove(struct platform_device= *pdev) =20 v4l2_device_unregister(&isc->v4l2_dev); =20 - clk_disable_unprepare(isc->ispck); clk_disable_unprepare(isc->hclock); =20 isc_clk_cleanup(isc); @@ -568,7 +567,6 @@ static int __maybe_unused xisc_runtime_suspend(struct d= evice *dev) { struct isc_device *isc =3D dev_get_drvdata(dev); =20 - clk_disable_unprepare(isc->ispck); clk_disable_unprepare(isc->hclock); =20 return 0; @@ -583,10 +581,6 @@ static int __maybe_unused xisc_runtime_resume(struct d= evice *dev) if (ret) return ret; =20 - ret =3D clk_prepare_enable(isc->ispck); - if (ret) - clk_disable_unprepare(isc->hclock); - return ret; } =20 diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/plat= form/coda/coda-common.c index 9a2640a9c75c..4a553f42ff0a 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -408,6 +408,7 @@ static struct vdoa_data *coda_get_vdoa_data(void) if (!vdoa_data) vdoa_data =3D ERR_PTR(-EPROBE_DEFER); =20 + put_device(&vdoa_pdev->dev); out: of_node_put(vdoa_node); =20 diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform= /davinci/vpif.c index 5a89d885d0e3..4a260f4ed236 100644 --- a/drivers/media/platform/davinci/vpif.c +++ b/drivers/media/platform/davinci/vpif.c @@ -41,6 +41,11 @@ MODULE_ALIAS("platform:" VPIF_DRIVER_NAME); #define VPIF_CH2_MAX_MODES 15 #define VPIF_CH3_MAX_MODES 2 =20 +struct vpif_data { + struct platform_device *capture; + struct platform_device *display; +}; + DEFINE_SPINLOCK(vpif_lock); EXPORT_SYMBOL_GPL(vpif_lock); =20 @@ -423,16 +428,31 @@ int vpif_channel_getfid(u8 channel_id) } EXPORT_SYMBOL(vpif_channel_getfid); =20 +static void vpif_pdev_release(struct device *dev) +{ + struct platform_device *pdev =3D to_platform_device(dev); + + kfree(pdev); +} + static int vpif_probe(struct platform_device *pdev) { static struct resource *res_irq; struct platform_device *pdev_capture, *pdev_display; struct device_node *endpoint =3D NULL; + struct vpif_data *data; + int ret; =20 vpif_base =3D devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(vpif_base)) return PTR_ERR(vpif_base); =20 + data =3D kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + platform_set_drvdata(pdev, data); + pm_runtime_enable(&pdev->dev); pm_runtime_get(&pdev->dev); =20 @@ -456,46 +476,79 @@ static int vpif_probe(struct platform_device *pdev) res_irq =3D platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res_irq) { dev_warn(&pdev->dev, "Missing IRQ resource.\n"); - pm_runtime_put(&pdev->dev); - return -EINVAL; + ret =3D -EINVAL; + goto err_put_rpm; } =20 - pdev_capture =3D devm_kzalloc(&pdev->dev, sizeof(*pdev_capture), - GFP_KERNEL); - if (pdev_capture) { - pdev_capture->name =3D "vpif_capture"; - pdev_capture->id =3D -1; - pdev_capture->resource =3D res_irq; - pdev_capture->num_resources =3D 1; - pdev_capture->dev.dma_mask =3D pdev->dev.dma_mask; - pdev_capture->dev.coherent_dma_mask =3D pdev->dev.coherent_dma_mask; - pdev_capture->dev.parent =3D &pdev->dev; - platform_device_register(pdev_capture); - } else { - dev_warn(&pdev->dev, "Unable to allocate memory for pdev_capture.\n"); + pdev_capture =3D kzalloc(sizeof(*pdev_capture), GFP_KERNEL); + if (!pdev_capture) { + ret =3D -ENOMEM; + goto err_put_rpm; } =20 - pdev_display =3D devm_kzalloc(&pdev->dev, sizeof(*pdev_display), - GFP_KERNEL); - if (pdev_display) { - pdev_display->name =3D "vpif_display"; - pdev_display->id =3D -1; - pdev_display->resource =3D res_irq; - pdev_display->num_resources =3D 1; - pdev_display->dev.dma_mask =3D pdev->dev.dma_mask; - pdev_display->dev.coherent_dma_mask =3D pdev->dev.coherent_dma_mask; - pdev_display->dev.parent =3D &pdev->dev; - platform_device_register(pdev_display); - } else { - dev_warn(&pdev->dev, "Unable to allocate memory for pdev_display.\n"); + pdev_capture->name =3D "vpif_capture"; + pdev_capture->id =3D -1; + pdev_capture->resource =3D res_irq; + pdev_capture->num_resources =3D 1; + pdev_capture->dev.dma_mask =3D pdev->dev.dma_mask; + pdev_capture->dev.coherent_dma_mask =3D pdev->dev.coherent_dma_mask; + pdev_capture->dev.parent =3D &pdev->dev; + pdev_capture->dev.release =3D vpif_pdev_release; + + ret =3D platform_device_register(pdev_capture); + if (ret) + goto err_put_pdev_capture; + + pdev_display =3D kzalloc(sizeof(*pdev_display), GFP_KERNEL); + if (!pdev_display) { + ret =3D -ENOMEM; + goto err_put_pdev_capture; } =20 + pdev_display->name =3D "vpif_display"; + pdev_display->id =3D -1; + pdev_display->resource =3D res_irq; + pdev_display->num_resources =3D 1; + pdev_display->dev.dma_mask =3D pdev->dev.dma_mask; + pdev_display->dev.coherent_dma_mask =3D pdev->dev.coherent_dma_mask; + pdev_display->dev.parent =3D &pdev->dev; + pdev_display->dev.release =3D vpif_pdev_release; + + ret =3D platform_device_register(pdev_display); + if (ret) + goto err_put_pdev_display; + + data->capture =3D pdev_capture; + data->display =3D pdev_display; + return 0; + +err_put_pdev_display: + platform_device_put(pdev_display); +err_put_pdev_capture: + platform_device_put(pdev_capture); +err_put_rpm: + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); + kfree(data); + + return ret; } =20 static int vpif_remove(struct platform_device *pdev) { + struct vpif_data *data =3D platform_get_drvdata(pdev); + + if (data->capture) + platform_device_unregister(data->capture); + if (data->display) + platform_device_unregister(data->display); + + pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); + + kfree(data); + return 0; } =20 diff --git a/drivers/media/platform/imx-jpeg/mxc-jpeg.c b/drivers/media/pla= tform/imx-jpeg/mxc-jpeg.c index 4ca96cf9def7..83a2b4d13bad 100644 --- a/drivers/media/platform/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/imx-jpeg/mxc-jpeg.c @@ -947,8 +947,13 @@ static void mxc_jpeg_device_run(void *priv) v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); =20 jpeg_src_buf =3D vb2_to_mxc_buf(&src_buf->vb2_buf); + if (q_data_cap->fmt->colplanes !=3D dst_buf->vb2_buf.num_planes) { + dev_err(dev, "Capture format %s has %d planes, but capture buffer has %d= planes\n", + q_data_cap->fmt->name, q_data_cap->fmt->colplanes, + dst_buf->vb2_buf.num_planes); + jpeg_src_buf->jpeg_parse_error =3D true; + } if (jpeg_src_buf->jpeg_parse_error) { - jpeg->slot_data[ctx->slot].used =3D false; v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); diff --git a/drivers/media/platform/meson/ge2d/ge2d.c b/drivers/media/platf= orm/meson/ge2d/ge2d.c index ccda18e5a377..5e7b319f300d 100644 --- a/drivers/media/platform/meson/ge2d/ge2d.c +++ b/drivers/media/platform/meson/ge2d/ge2d.c @@ -215,35 +215,35 @@ static void ge2d_hw_start(struct meson_ge2d *ge2d) =20 regmap_write(ge2d->map, GE2D_SRC1_CLIPY_START_END, FIELD_PREP(GE2D_START, ctx->in.crop.top) | - FIELD_PREP(GE2D_END, ctx->in.crop.top + ctx->in.crop.height)); + FIELD_PREP(GE2D_END, ctx->in.crop.top + ctx->in.crop.height - 1)); regmap_write(ge2d->map, GE2D_SRC1_CLIPX_START_END, FIELD_PREP(GE2D_START, ctx->in.crop.left) | - FIELD_PREP(GE2D_END, ctx->in.crop.left + ctx->in.crop.width)); + FIELD_PREP(GE2D_END, ctx->in.crop.left + ctx->in.crop.width - 1)); regmap_write(ge2d->map, GE2D_SRC2_CLIPY_START_END, FIELD_PREP(GE2D_START, ctx->out.crop.top) | - FIELD_PREP(GE2D_END, ctx->out.crop.top + ctx->out.crop.height)); + FIELD_PREP(GE2D_END, ctx->out.crop.top + ctx->out.crop.height - 1)); regmap_write(ge2d->map, GE2D_SRC2_CLIPX_START_END, FIELD_PREP(GE2D_START, ctx->out.crop.left) | - FIELD_PREP(GE2D_END, ctx->out.crop.left + ctx->out.crop.width)); + FIELD_PREP(GE2D_END, ctx->out.crop.left + ctx->out.crop.width - 1)); regmap_write(ge2d->map, GE2D_DST_CLIPY_START_END, FIELD_PREP(GE2D_START, ctx->out.crop.top) | - FIELD_PREP(GE2D_END, ctx->out.crop.top + ctx->out.crop.height)); + FIELD_PREP(GE2D_END, ctx->out.crop.top + ctx->out.crop.height - 1)); regmap_write(ge2d->map, GE2D_DST_CLIPX_START_END, FIELD_PREP(GE2D_START, ctx->out.crop.left) | - FIELD_PREP(GE2D_END, ctx->out.crop.left + ctx->out.crop.width)); + FIELD_PREP(GE2D_END, ctx->out.crop.left + ctx->out.crop.width - 1)); =20 regmap_write(ge2d->map, GE2D_SRC1_Y_START_END, - FIELD_PREP(GE2D_END, ctx->in.pix_fmt.height)); + FIELD_PREP(GE2D_END, ctx->in.pix_fmt.height - 1)); regmap_write(ge2d->map, GE2D_SRC1_X_START_END, - FIELD_PREP(GE2D_END, ctx->in.pix_fmt.width)); + FIELD_PREP(GE2D_END, ctx->in.pix_fmt.width - 1)); regmap_write(ge2d->map, GE2D_SRC2_Y_START_END, - FIELD_PREP(GE2D_END, ctx->out.pix_fmt.height)); + FIELD_PREP(GE2D_END, ctx->out.pix_fmt.height - 1)); regmap_write(ge2d->map, GE2D_SRC2_X_START_END, - FIELD_PREP(GE2D_END, ctx->out.pix_fmt.width)); + FIELD_PREP(GE2D_END, ctx->out.pix_fmt.width - 1)); regmap_write(ge2d->map, GE2D_DST_Y_START_END, - FIELD_PREP(GE2D_END, ctx->out.pix_fmt.height)); + FIELD_PREP(GE2D_END, ctx->out.pix_fmt.height - 1)); regmap_write(ge2d->map, GE2D_DST_X_START_END, - FIELD_PREP(GE2D_END, ctx->out.pix_fmt.width)); + FIELD_PREP(GE2D_END, ctx->out.pix_fmt.width - 1)); =20 /* Color, no blend, use source color */ reg =3D GE2D_ALU_DO_COLOR_OPERATION_LOGIC(LOGIC_OPERATION_COPY, diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_vpu.c b/driver= s/media/platform/mtk-vcodec/mtk_vcodec_fw_vpu.c index cd27f637dbe7..cfc7ebed8fb7 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_vpu.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_vpu.c @@ -102,6 +102,8 @@ struct mtk_vcodec_fw *mtk_vcodec_fw_vpu_init(struct mtk= _vcodec_dev *dev, vpu_wdt_reg_handler(fw_pdev, mtk_vcodec_vpu_reset_handler, dev, rst_id); =20 fw =3D devm_kzalloc(&dev->plat_dev->dev, sizeof(*fw), GFP_KERNEL); + if (!fw) + return ERR_PTR(-ENOMEM); fw->type =3D VPU; fw->ops =3D &mtk_vcodec_vpu_msg; fw->pdev =3D fw_pdev; diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/plat= form/omap3isp/ispstat.c index 5b9b57f4d9bf..68cf68dbcace 100644 --- a/drivers/media/platform/omap3isp/ispstat.c +++ b/drivers/media/platform/omap3isp/ispstat.c @@ -512,7 +512,7 @@ int omap3isp_stat_request_statistics(struct ispstat *st= at, int omap3isp_stat_request_statistics_time32(struct ispstat *stat, struct omap3isp_stat_data_time32 *data) { - struct omap3isp_stat_data data64; + struct omap3isp_stat_data data64 =3D { }; int ret; =20 ret =3D omap3isp_stat_request_statistics(stat, &data64); @@ -521,7 +521,8 @@ int omap3isp_stat_request_statistics_time32(struct isps= tat *stat, =20 data->ts.tv_sec =3D data64.ts.tv_sec; data->ts.tv_usec =3D data64.ts.tv_usec; - memcpy(&data->buf, &data64.buf, sizeof(*data) - sizeof(data->ts)); + data->buf =3D (uintptr_t)data64.buf; + memcpy(&data->frame, &data64.frame, sizeof(data->frame)); =20 return 0; } diff --git a/drivers/media/platform/qcom/camss/camss-csid-170.c b/drivers/m= edia/platform/qcom/camss/camss-csid-170.c index ac22ff29d2a9..82f59933ad7b 100644 --- a/drivers/media/platform/qcom/camss/camss-csid-170.c +++ b/drivers/media/platform/qcom/camss/camss-csid-170.c @@ -105,7 +105,8 @@ #define CSID_RDI_CTRL(rdi) ((IS_LITE ? 0x208 : 0x308)\ + 0x100 * (rdi)) #define RDI_CTRL_HALT_CMD 0 -#define ALT_CMD_RESUME_AT_FRAME_BOUNDARY 1 +#define HALT_CMD_HALT_AT_FRAME_BOUNDARY 0 +#define HALT_CMD_RESUME_AT_FRAME_BOUNDARY 1 #define RDI_CTRL_HALT_MODE 2 =20 #define CSID_RDI_FRM_DROP_PATTERN(rdi) ((IS_LITE ? 0x20C : 0x30C)\ @@ -366,7 +367,7 @@ static void csid_configure_stream(struct csid_device *c= sid, u8 enable) val |=3D input_format->width & 0x1fff << TPG_DT_n_CFG_0_FRAME_WIDTH; writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_0(0)); =20 - val =3D DATA_TYPE_RAW_10BIT << TPG_DT_n_CFG_1_DATA_TYPE; + val =3D format->data_type << TPG_DT_n_CFG_1_DATA_TYPE; writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_1(0)); =20 val =3D tg->mode << TPG_DT_n_CFG_2_PAYLOAD_MODE; @@ -382,8 +383,9 @@ static void csid_configure_stream(struct csid_device *c= sid, u8 enable) val =3D 1 << RDI_CFG0_BYTE_CNTR_EN; val |=3D 1 << RDI_CFG0_FORMAT_MEASURE_EN; val |=3D 1 << RDI_CFG0_TIMESTAMP_EN; + /* note: for non-RDI path, this should be format->decode_format */ val |=3D DECODE_FORMAT_PAYLOAD_ONLY << RDI_CFG0_DECODE_FORMAT; - val |=3D DATA_TYPE_RAW_10BIT << RDI_CFG0_DATA_TYPE; + val |=3D format->data_type << RDI_CFG0_DATA_TYPE; val |=3D vc << RDI_CFG0_VIRTUAL_CHANNEL; val |=3D dt_id << RDI_CFG0_DT_ID; writel_relaxed(val, csid->base + CSID_RDI_CFG0(0)); @@ -443,13 +445,10 @@ static void csid_configure_stream(struct csid_device = *csid, u8 enable) val |=3D 1 << CSI2_RX_CFG1_MISR_EN; writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG1); // csi2_vc_mode_shif= t_val ? =20 - /* error irqs start at BIT(11) */ - writel_relaxed(~0u, csid->base + CSID_CSI2_RX_IRQ_MASK); - - /* RDI irq */ - writel_relaxed(~0u, csid->base + CSID_TOP_IRQ_MASK); - - val =3D 1 << RDI_CTRL_HALT_CMD; + if (enable) + val =3D HALT_CMD_RESUME_AT_FRAME_BOUNDARY << RDI_CTRL_HALT_CMD; + else + val =3D HALT_CMD_HALT_AT_FRAME_BOUNDARY << RDI_CTRL_HALT_CMD; writel_relaxed(val, csid->base + CSID_RDI_CTRL(0)); } =20 diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/me= dia/platform/qcom/camss/camss-vfe-170.c index 5c083d70d495..af71dc659bb9 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-170.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c @@ -402,17 +402,7 @@ static irqreturn_t vfe_isr(int irq, void *dev) */ static int vfe_halt(struct vfe_device *vfe) { - unsigned long time; - - reinit_completion(&vfe->halt_complete); - - time =3D wait_for_completion_timeout(&vfe->halt_complete, - msecs_to_jiffies(VFE_HALT_TIMEOUT_MS)); - if (!time) { - dev_err(vfe->camss->dev, "VFE halt timeout\n"); - return -EIO; - } - + /* rely on vfe_disable_output() to stop the VFE */ return 0; } =20 diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/pl= atform/qcom/venus/helpers.c index 84c3a511ec31..0bca95d01650 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -189,7 +189,6 @@ int venus_helper_alloc_dpb_bufs(struct venus_inst *inst) buf->va =3D dma_alloc_attrs(dev, buf->size, &buf->da, GFP_KERNEL, buf->attrs); if (!buf->va) { - kfree(buf); ret =3D -ENOMEM; goto fail; } @@ -209,6 +208,7 @@ int venus_helper_alloc_dpb_bufs(struct venus_inst *inst) return 0; =20 fail: + kfree(buf); venus_helper_free_dpb_bufs(inst); return ret; } diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.c b/drivers/media/p= latform/qcom/venus/hfi_cmds.c index 5aea07307e02..4ecd444050bb 100644 --- a/drivers/media/platform/qcom/venus/hfi_cmds.c +++ b/drivers/media/platform/qcom/venus/hfi_cmds.c @@ -1054,6 +1054,8 @@ static int pkt_session_set_property_1x(struct hfi_ses= sion_set_property_pkt *pkt, pkt->shdr.hdr.size +=3D sizeof(u32) + sizeof(*info); break; } + case HFI_PROPERTY_PARAM_VENC_HDR10_PQ_SEI: + return -ENOTSUPP; =20 /* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */ case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS: diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platf= orm/qcom/venus/venc.c index 84bafc3118cc..adea4c3b8c20 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -662,8 +662,8 @@ static int venc_set_properties(struct venus_inst *inst) =20 ptype =3D HFI_PROPERTY_PARAM_VENC_H264_TRANSFORM_8X8; h264_transform.enable_type =3D 0; - if (ctr->profile.h264 =3D=3D HFI_H264_PROFILE_HIGH || - ctr->profile.h264 =3D=3D HFI_H264_PROFILE_CONSTRAINED_HIGH) + if (ctr->profile.h264 =3D=3D V4L2_MPEG_VIDEO_H264_PROFILE_HIGH || + ctr->profile.h264 =3D=3D V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HI= GH) h264_transform.enable_type =3D ctr->h264_8x8_transform; =20 ret =3D hfi_session_set_property(inst, ptype, &h264_transform); diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media= /platform/qcom/venus/venc_ctrls.c index 1ada42df314d..ea5805e71c14 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -320,8 +320,8 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) ctr->intra_refresh_period =3D ctrl->val; break; case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: - if (ctr->profile.h264 !=3D HFI_H264_PROFILE_HIGH && - ctr->profile.h264 !=3D HFI_H264_PROFILE_CONSTRAINED_HIGH) + if (ctr->profile.h264 !=3D V4L2_MPEG_VIDEO_H264_PROFILE_HIGH && + ctr->profile.h264 !=3D V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) return -EINVAL; =20 /* @@ -457,7 +457,7 @@ int venc_ctrl_init(struct venus_inst *inst) V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP, 1, 51, 1, 1); =20 v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, 0, 1, 1, 0); + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, 0, 1, 1, 1); =20 v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP, 1, 51, 1, 1); diff --git a/drivers/media/platform/ti-vpe/cal-video.c b/drivers/media/plat= form/ti-vpe/cal-video.c index 7799da1cc261..3e936a2ca36c 100644 --- a/drivers/media/platform/ti-vpe/cal-video.c +++ b/drivers/media/platform/ti-vpe/cal-video.c @@ -823,6 +823,9 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ct= x) /* Enumerate sub device formats and enable all matching local formats */ ctx->active_fmt =3D devm_kcalloc(ctx->cal->dev, cal_num_formats, sizeof(*ctx->active_fmt), GFP_KERNEL); + if (!ctx->active_fmt) + return -ENOMEM; + ctx->num_active_fmt =3D 0; =20 for (j =3D 0, i =3D 0; ; ++j) { diff --git a/drivers/media/rc/gpio-ir-tx.c b/drivers/media/rc/gpio-ir-tx.c index c6cd2e6d8e65..a50701cfbbd7 100644 --- a/drivers/media/rc/gpio-ir-tx.c +++ b/drivers/media/rc/gpio-ir-tx.c @@ -48,11 +48,29 @@ static int gpio_ir_tx_set_carrier(struct rc_dev *dev, u= 32 carrier) return 0; } =20 +static void delay_until(ktime_t until) +{ + /* + * delta should never exceed 0.5 seconds (IR_MAX_DURATION) and on + * m68k ndelay(s64) does not compile; so use s32 rather than s64. + */ + s32 delta; + + while (true) { + delta =3D ktime_us_delta(until, ktime_get()); + if (delta <=3D 0) + return; + + /* udelay more than 1ms may not work */ + delta =3D min(delta, 1000); + udelay(delta); + } +} + static void gpio_ir_tx_unmodulated(struct gpio_ir *gpio_ir, uint *txbuf, uint count) { ktime_t edge; - s32 delta; int i; =20 local_irq_disable(); @@ -63,9 +81,7 @@ static void gpio_ir_tx_unmodulated(struct gpio_ir *gpio_i= r, uint *txbuf, gpiod_set_value(gpio_ir->gpio, !(i % 2)); =20 edge =3D ktime_add_us(edge, txbuf[i]); - delta =3D ktime_us_delta(edge, ktime_get()); - if (delta > 0) - udelay(delta); + delay_until(edge); } =20 gpiod_set_value(gpio_ir->gpio, 0); @@ -97,9 +113,7 @@ static void gpio_ir_tx_modulated(struct gpio_ir *gpio_ir= , uint *txbuf, if (i % 2) { // space edge =3D ktime_add_us(edge, txbuf[i]); - delta =3D ktime_us_delta(edge, ktime_get()); - if (delta > 0) - udelay(delta); + delay_until(edge); } else { // pulse ktime_t last =3D ktime_add_us(edge, txbuf[i]); diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c index 7e98e7e3aace..196806709259 100644 --- a/drivers/media/rc/ir_toy.c +++ b/drivers/media/rc/ir_toy.c @@ -458,7 +458,7 @@ static int irtoy_probe(struct usb_interface *intf, err =3D usb_submit_urb(irtoy->urb_in, GFP_KERNEL); if (err !=3D 0) { dev_err(irtoy->dev, "fail to submit in urb: %d\n", err); - return err; + goto free_rcdev; } =20 err =3D irtoy_setup(irtoy); diff --git a/drivers/media/test-drivers/vidtv/vidtv_s302m.c b/drivers/media= /test-drivers/vidtv/vidtv_s302m.c index d79b65854627..4676083cee3b 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_s302m.c +++ b/drivers/media/test-drivers/vidtv/vidtv_s302m.c @@ -455,6 +455,9 @@ struct vidtv_encoder e->name =3D kstrdup(args.name, GFP_KERNEL); =20 e->encoder_buf =3D vzalloc(VIDTV_S302M_BUF_SZ); + if (!e->encoder_buf) + goto out_kfree_e; + e->encoder_buf_sz =3D VIDTV_S302M_BUF_SZ; e->encoder_buf_offset =3D 0; =20 @@ -467,10 +470,8 @@ struct vidtv_encoder e->is_video_encoder =3D false; =20 ctx =3D kzalloc(priv_sz, GFP_KERNEL); - if (!ctx) { - kfree(e); - return NULL; - } + if (!ctx) + goto out_kfree_buf; =20 e->ctx =3D ctx; ctx->last_duration =3D 0; @@ -498,6 +499,14 @@ struct vidtv_encoder e->next =3D NULL; =20 return e; + +out_kfree_buf: + kfree(e->encoder_buf); + +out_kfree_e: + kfree(e->name); + kfree(e); + return NULL; } =20 void vidtv_s302m_encoder_destroy(struct vidtv_encoder *e) diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em= 28xx/em28xx-cards.c index b451ce3cb169..ae25d2cbfdfe 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -3936,6 +3936,8 @@ static int em28xx_usb_probe(struct usb_interface *int= f, goto err_free; } =20 + kref_init(&dev->ref); + dev->devno =3D nr; dev->model =3D id->driver_info; dev->alt =3D -1; @@ -4036,6 +4038,8 @@ static int em28xx_usb_probe(struct usb_interface *int= f, } =20 if (dev->board.has_dual_ts && em28xx_duplicate_dev(dev) =3D=3D 0) { + kref_init(&dev->dev_next->ref); + dev->dev_next->ts =3D SECONDARY_TS; dev->dev_next->alt =3D -1; dev->dev_next->is_audio_only =3D has_vendor_audio && @@ -4090,12 +4094,8 @@ static int em28xx_usb_probe(struct usb_interface *in= tf, em28xx_write_reg(dev, 0x0b, 0x82); mdelay(100); } - - kref_init(&dev->dev_next->ref); } =20 - kref_init(&dev->ref); - request_modules(dev); =20 /* @@ -4150,11 +4150,8 @@ static void em28xx_usb_disconnect(struct usb_interfa= ce *intf) =20 em28xx_close_extension(dev); =20 - if (dev->dev_next) { - em28xx_close_extension(dev->dev_next); + if (dev->dev_next) em28xx_release_resources(dev->dev_next); - } - em28xx_release_resources(dev); =20 if (dev->dev_next) { diff --git a/drivers/media/usb/go7007/s2250-board.c b/drivers/media/usb/go7= 007/s2250-board.c index c742cc88fac5..1fa6f10ee157 100644 --- a/drivers/media/usb/go7007/s2250-board.c +++ b/drivers/media/usb/go7007/s2250-board.c @@ -504,6 +504,7 @@ static int s2250_probe(struct i2c_client *client, u8 *data; struct go7007 *go =3D i2c_get_adapdata(adapter); struct go7007_usb *usb =3D go->hpi_context; + int err =3D -EIO; =20 audio =3D i2c_new_dummy_device(adapter, TLV320_ADDRESS >> 1); if (IS_ERR(audio)) @@ -532,11 +533,8 @@ static int s2250_probe(struct i2c_client *client, V4L2_CID_HUE, -512, 511, 1, 0); sd->ctrl_handler =3D &state->hdl; if (state->hdl.error) { - int err =3D state->hdl.error; - - v4l2_ctrl_handler_free(&state->hdl); - kfree(state); - return err; + err =3D state->hdl.error; + goto fail; } =20 state->std =3D V4L2_STD_NTSC; @@ -600,7 +598,7 @@ static int s2250_probe(struct i2c_client *client, i2c_unregister_device(audio); v4l2_ctrl_handler_free(&state->hdl); kfree(state); - return -EIO; + return err; } =20 static int s2250_remove(struct i2c_client *client) diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpv= r/hdpvr-video.c index 563128d11731..60e57e0f1927 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -308,7 +308,6 @@ static int hdpvr_start_streaming(struct hdpvr_device *d= ev) =20 dev->status =3D STATUS_STREAMING; =20 - INIT_WORK(&dev->worker, hdpvr_transmit_buffers); schedule_work(&dev->worker); =20 v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, @@ -1165,6 +1164,9 @@ int hdpvr_register_videodev(struct hdpvr_device *dev,= struct device *parent, bool ac3 =3D dev->flags & HDPVR_FLAG_AC3_CAP; int res; =20 + // initialize dev->worker + INIT_WORK(&dev->worker, hdpvr_transmit_buffers); + dev->cur_std =3D V4L2_STD_525_60; dev->width =3D 720; dev->height =3D 480; diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/s= tk1160/stk1160-core.c index 4e1698f78818..ce717502ea4c 100644 --- a/drivers/media/usb/stk1160/stk1160-core.c +++ b/drivers/media/usb/stk1160/stk1160-core.c @@ -403,7 +403,7 @@ static void stk1160_disconnect(struct usb_interface *in= terface) /* Here is the only place where isoc get released */ stk1160_uninit_isoc(dev); =20 - stk1160_clear_queue(dev); + stk1160_clear_queue(dev, VB2_BUF_STATE_ERROR); =20 video_unregister_device(&dev->vdev); v4l2_device_disconnect(&dev->v4l2_dev); diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/st= k1160/stk1160-v4l.c index 6a4eb616d516..1aa953469402 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -258,7 +258,7 @@ static int stk1160_start_streaming(struct stk1160 *dev) stk1160_uninit_isoc(dev); out_stop_hw: usb_set_interface(dev->udev, 0, 0); - stk1160_clear_queue(dev); + stk1160_clear_queue(dev, VB2_BUF_STATE_QUEUED); =20 mutex_unlock(&dev->v4l_lock); =20 @@ -306,7 +306,7 @@ static int stk1160_stop_streaming(struct stk1160 *dev) =20 stk1160_stop_hw(dev); =20 - stk1160_clear_queue(dev); + stk1160_clear_queue(dev, VB2_BUF_STATE_ERROR); =20 stk1160_dbg("streaming stopped\n"); =20 @@ -745,7 +745,7 @@ static const struct video_device v4l_template =3D { /********************************************************************/ =20 /* Must be called with both v4l_lock and vb_queue_lock hold */ -void stk1160_clear_queue(struct stk1160 *dev) +void stk1160_clear_queue(struct stk1160 *dev, enum vb2_buffer_state vb2_st= ate) { struct stk1160_buffer *buf; unsigned long flags; @@ -756,7 +756,7 @@ void stk1160_clear_queue(struct stk1160 *dev) buf =3D list_first_entry(&dev->avail_bufs, struct stk1160_buffer, list); list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + vb2_buffer_done(&buf->vb.vb2_buf, vb2_state); stk1160_dbg("buffer [%p/%d] aborted\n", buf, buf->vb.vb2_buf.index); } @@ -766,7 +766,7 @@ void stk1160_clear_queue(struct stk1160 *dev) buf =3D dev->isoc_ctl.buf; dev->isoc_ctl.buf =3D NULL; =20 - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + vb2_buffer_done(&buf->vb.vb2_buf, vb2_state); stk1160_dbg("buffer [%p/%d] aborted\n", buf, buf->vb.vb2_buf.index); } diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk116= 0/stk1160.h index a31ea1c80f25..a70963ce8753 100644 --- a/drivers/media/usb/stk1160/stk1160.h +++ b/drivers/media/usb/stk1160/stk1160.h @@ -166,7 +166,7 @@ struct regval { int stk1160_vb2_setup(struct stk1160 *dev); int stk1160_video_register(struct stk1160 *dev); void stk1160_video_unregister(struct stk1160 *dev); -void stk1160_clear_queue(struct stk1160 *dev); +void stk1160_clear_queue(struct stk1160 *dev, enum vb2_buffer_state vb2_st= ate); =20 /* Provided by stk1160-video.c */ int stk1160_alloc_isoc(struct stk1160 *dev); diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2= -core/v4l2-ctrls-core.c index 70adfc1b9c81..fb9b99e9e12b 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c @@ -113,6 +113,7 @@ static void std_init_compound(const struct v4l2_ctrl *c= trl, u32 idx, struct v4l2_ctrl_mpeg2_quantisation *p_mpeg2_quant; struct v4l2_ctrl_vp8_frame *p_vp8_frame; struct v4l2_ctrl_fwht_params *p_fwht_params; + struct v4l2_ctrl_h264_scaling_matrix *p_h264_scaling_matrix; void *p =3D ptr.p + idx * ctrl->elem_size; =20 if (ctrl->p_def.p_const) @@ -160,6 +161,15 @@ static void std_init_compound(const struct v4l2_ctrl *= ctrl, u32 idx, p_fwht_params->flags =3D V4L2_FWHT_FL_PIXENC_YUV | (2 << V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET); break; + case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: + p_h264_scaling_matrix =3D p; + /* + * The default (flat) H.264 scaling matrix when none are + * specified in the bitstream, this is according to formulas + * (7-8) and (7-9) of the specification. + */ + memset(p_h264_scaling_matrix, 16, sizeof(*p_h264_scaling_matrix)); + break; } } =20 diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core= /v4l2-ioctl.c index 69b74d0e8a90..059d6debb25d 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -279,8 +279,8 @@ static void v4l_print_format(const void *arg, bool writ= e_only) const struct v4l2_vbi_format *vbi; const struct v4l2_sliced_vbi_format *sliced; const struct v4l2_window *win; - const struct v4l2_sdr_format *sdr; const struct v4l2_meta_format *meta; + u32 pixelformat; u32 planes; unsigned i; =20 @@ -299,8 +299,9 @@ static void v4l_print_format(const void *arg, bool writ= e_only) case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: mp =3D &p->fmt.pix_mp; + pixelformat =3D mp->pixelformat; pr_cont(", width=3D%u, height=3D%u, format=3D%p4cc, field=3D%s, colorspa= ce=3D%d, num_planes=3D%u, flags=3D0x%x, ycbcr_enc=3D%u, quantization=3D%u, = xfer_func=3D%u\n", - mp->width, mp->height, &mp->pixelformat, + mp->width, mp->height, &pixelformat, prt_names(mp->field, v4l2_field_names), mp->colorspace, mp->num_planes, mp->flags, mp->ycbcr_enc, mp->quantization, mp->xfer_func); @@ -343,14 +344,15 @@ static void v4l_print_format(const void *arg, bool wr= ite_only) break; case V4L2_BUF_TYPE_SDR_CAPTURE: case V4L2_BUF_TYPE_SDR_OUTPUT: - sdr =3D &p->fmt.sdr; - pr_cont(", pixelformat=3D%p4cc\n", &sdr->pixelformat); + pixelformat =3D p->fmt.sdr.pixelformat; + pr_cont(", pixelformat=3D%p4cc\n", &pixelformat); break; case V4L2_BUF_TYPE_META_CAPTURE: case V4L2_BUF_TYPE_META_OUTPUT: meta =3D &p->fmt.meta; + pixelformat =3D meta->dataformat; pr_cont(", dataformat=3D%p4cc, buffersize=3D%u\n", - &meta->dataformat, meta->buffersize); + &pixelformat, meta->buffersize); break; } } diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-co= re/v4l2-mem2mem.c index e7f4bf5bc8dd..3de683b5e06d 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -585,19 +585,14 @@ int v4l2_m2m_reqbufs(struct file *file, struct v4l2_m= 2m_ctx *m2m_ctx, } EXPORT_SYMBOL_GPL(v4l2_m2m_reqbufs); =20 -int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, - struct v4l2_buffer *buf) +static void v4l2_m2m_adjust_mem_offset(struct vb2_queue *vq, + struct v4l2_buffer *buf) { - struct vb2_queue *vq; - int ret =3D 0; - unsigned int i; - - vq =3D v4l2_m2m_get_vq(m2m_ctx, buf->type); - ret =3D vb2_querybuf(vq, buf); - /* Adjust MMAP memory offsets for the CAPTURE queue */ if (buf->memory =3D=3D V4L2_MEMORY_MMAP && V4L2_TYPE_IS_CAPTURE(vq->type)= ) { if (V4L2_TYPE_IS_MULTIPLANAR(vq->type)) { + unsigned int i; + for (i =3D 0; i < buf->length; ++i) buf->m.planes[i].m.mem_offset +=3D DST_QUEUE_OFF_BASE; @@ -605,8 +600,23 @@ int v4l2_m2m_querybuf(struct file *file, struct v4l2_m= 2m_ctx *m2m_ctx, buf->m.offset +=3D DST_QUEUE_OFF_BASE; } } +} =20 - return ret; +int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, + struct v4l2_buffer *buf) +{ + struct vb2_queue *vq; + int ret; + + vq =3D v4l2_m2m_get_vq(m2m_ctx, buf->type); + ret =3D vb2_querybuf(vq, buf); + if (ret) + return ret; + + /* Adjust MMAP memory offsets for the CAPTURE queue */ + v4l2_m2m_adjust_mem_offset(vq, buf); + + return 0; } EXPORT_SYMBOL_GPL(v4l2_m2m_querybuf); =20 @@ -763,6 +773,9 @@ int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ct= x *m2m_ctx, if (ret) return ret; =20 + /* Adjust MMAP memory offsets for the CAPTURE queue */ + v4l2_m2m_adjust_mem_offset(vq, buf); + /* * If the capture queue is streaming, but streaming hasn't started * on the device, but was asked to stop, mark the previously queued @@ -784,9 +797,17 @@ int v4l2_m2m_dqbuf(struct file *file, struct v4l2_m2m_= ctx *m2m_ctx, struct v4l2_buffer *buf) { struct vb2_queue *vq; + int ret; =20 vq =3D v4l2_m2m_get_vq(m2m_ctx, buf->type); - return vb2_dqbuf(vq, buf, file->f_flags & O_NONBLOCK); + ret =3D vb2_dqbuf(vq, buf, file->f_flags & O_NONBLOCK); + if (ret) + return ret; + + /* Adjust MMAP memory offsets for the CAPTURE queue */ + v4l2_m2m_adjust_mem_offset(vq, buf); + + return 0; } EXPORT_SYMBOL_GPL(v4l2_m2m_dqbuf); =20 @@ -795,9 +816,17 @@ int v4l2_m2m_prepare_buf(struct file *file, struct v4l= 2_m2m_ctx *m2m_ctx, { struct video_device *vdev =3D video_devdata(file); struct vb2_queue *vq; + int ret; =20 vq =3D v4l2_m2m_get_vq(m2m_ctx, buf->type); - return vb2_prepare_buf(vq, vdev->v4l2_dev->mdev, buf); + ret =3D vb2_prepare_buf(vq, vdev->v4l2_dev->mdev, buf); + if (ret) + return ret; + + /* Adjust MMAP memory offsets for the CAPTURE queue */ + v4l2_m2m_adjust_mem_offset(vq, buf); + + return 0; } EXPORT_SYMBOL_GPL(v4l2_m2m_prepare_buf); =20 diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index 762d0c0f0716..ecc78d6f89ed 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -1025,7 +1025,7 @@ static struct emif_data *__init_or_module get_device_= details( temp =3D devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); dev_info =3D devm_kzalloc(dev, sizeof(*dev_info), GFP_KERNEL); =20 - if (!emif || !pd || !dev_info) { + if (!emif || !temp || !dev_info) { dev_err(dev, "%s:%d: allocation error\n", __func__, __LINE__); goto error; } @@ -1117,7 +1117,7 @@ static int __init_or_module emif_probe(struct platfor= m_device *pdev) { struct emif_data *emif; struct resource *res; - int irq; + int irq, ret; =20 if (pdev->dev.of_node) emif =3D of_get_memory_device_details(pdev->dev.of_node, &pdev->dev); @@ -1147,7 +1147,9 @@ static int __init_or_module emif_probe(struct platfor= m_device *pdev) emif_onetime_settings(emif); emif_debugfs_init(emif); disable_and_clear_all_interrupts(emif); - setup_interrupts(emif, irq); + ret =3D setup_interrupts(emif, irq); + if (ret) + goto error; =20 /* One-time actions taken on probing the first device */ if (!emif1) { diff --git a/drivers/memory/tegra/tegra20-emc.c b/drivers/memory/tegra/tegr= a20-emc.c index 497b6edbf3ca..25ba3c5e4ad6 100644 --- a/drivers/memory/tegra/tegra20-emc.c +++ b/drivers/memory/tegra/tegra20-emc.c @@ -540,7 +540,7 @@ static int emc_read_lpddr_mode_register(struct tegra_em= c *emc, unsigned int register_addr, unsigned int *register_data) { - u32 memory_dev =3D emem_dev + 1; + u32 memory_dev =3D emem_dev ? 1 : 2; u32 val, mr_mask =3D 0xff; int err; =20 diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/ms= pro_block.c index c0450397b673..7ea312f0840e 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -186,13 +186,8 @@ static int mspro_block_bd_open(struct block_device *bd= ev, fmode_t mode) =20 mutex_lock(&mspro_block_disk_lock); =20 - if (msb && msb->card) { + if (msb && msb->card) msb->usage_count++; - if ((mode & FMODE_WRITE) && msb->read_only) - rc =3D -EROFS; - else - rc =3D 0; - } =20 mutex_unlock(&mspro_block_disk_lock); =20 @@ -1239,6 +1234,9 @@ static int mspro_block_init_disk(struct memstick_dev = *card) set_capacity(msb->disk, capacity); dev_dbg(&card->dev, "capacity set %ld\n", capacity); =20 + if (msb->read_only) + set_disk_ro(msb->disk, true); + rc =3D device_add_disk(&card->dev, msb->disk, NULL); if (rc) goto out_cleanup_disk; diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 8d58c8df46cf..56338f9dbd0b 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -906,14 +906,14 @@ static int __init asic3_mfd_probe(struct platform_dev= ice *pdev, ret =3D mfd_add_devices(&pdev->dev, pdev->id, &asic3_cell_ds1wm, 1, mem, asic->irq_base, NULL); if (ret < 0) - goto out; + goto out_unmap; } =20 if (mem_sdio && (irq >=3D 0)) { ret =3D mfd_add_devices(&pdev->dev, pdev->id, &asic3_cell_mmc, 1, mem_sdio, irq, NULL); if (ret < 0) - goto out; + goto out_unmap; } =20 ret =3D 0; @@ -927,8 +927,12 @@ static int __init asic3_mfd_probe(struct platform_devi= ce *pdev, ret =3D mfd_add_devices(&pdev->dev, 0, asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0, NULL); } + return ret; =20 - out: +out_unmap: + if (asic->tmio_cnf) + iounmap(asic->tmio_cnf); +out: return ret; } =20 diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 8a4f1d90dcfd..1000572761a8 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -323,8 +323,10 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx,= unsigned int mode, adc1 |=3D MC13783_ADC1_ATOX; =20 dev_dbg(mc13xxx->dev, "%s: request irq\n", __func__); - mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE, + ret =3D mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE, mc13xxx_handler_adcdone, __func__, &adcdone_data); + if (ret) + goto out; =20 mc13xxx_reg_write(mc13xxx, MC13XXX_ADC0, adc0); mc13xxx_reg_write(mc13xxx, MC13XXX_ADC1, adc1); diff --git a/drivers/misc/cardreader/alcor_pci.c b/drivers/misc/cardreader/= alcor_pci.c index de6d44a158bb..3f514d77a843 100644 --- a/drivers/misc/cardreader/alcor_pci.c +++ b/drivers/misc/cardreader/alcor_pci.c @@ -266,7 +266,7 @@ static int alcor_pci_probe(struct pci_dev *pdev, if (!priv) return -ENOMEM; =20 - ret =3D ida_simple_get(&alcor_pci_idr, 0, 0, GFP_KERNEL); + ret =3D ida_alloc(&alcor_pci_idr, GFP_KERNEL); if (ret < 0) return ret; priv->id =3D ret; @@ -280,7 +280,8 @@ static int alcor_pci_probe(struct pci_dev *pdev, ret =3D pci_request_regions(pdev, DRV_NAME_ALCOR_PCI); if (ret) { dev_err(&pdev->dev, "Cannot request region\n"); - return -ENOMEM; + ret =3D -ENOMEM; + goto error_free_ida; } =20 if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) { @@ -324,6 +325,8 @@ static int alcor_pci_probe(struct pci_dev *pdev, =20 error_release_regions: pci_release_regions(pdev); +error_free_ida: + ida_free(&alcor_pci_idr, priv->id); return ret; } =20 @@ -337,7 +340,7 @@ static void alcor_pci_remove(struct pci_dev *pdev) =20 mfd_remove_devices(&pdev->dev); =20 - ida_simple_remove(&alcor_pci_idr, priv->id); + ida_free(&alcor_pci_idr, priv->id); =20 pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); diff --git a/drivers/misc/habanalabs/common/debugfs.c b/drivers/misc/habana= labs/common/debugfs.c index 1f2a3dc6c4e2..78a6789ef7cc 100644 --- a/drivers/misc/habanalabs/common/debugfs.c +++ b/drivers/misc/habanalabs/common/debugfs.c @@ -856,6 +856,8 @@ static ssize_t hl_set_power_state(struct file *f, const= char __user *buf, pci_set_power_state(hdev->pdev, PCI_D0); pci_restore_state(hdev->pdev); rc =3D pci_enable_device(hdev->pdev); + if (rc < 0) + return rc; } else if (value =3D=3D 2) { pci_save_state(hdev->pdev); pci_disable_device(hdev->pdev); diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 67c5b452dd35..88b91ad8e541 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -1070,10 +1070,10 @@ static int kgdbts_option_setup(char *opt) { if (strlen(opt) >=3D MAX_CONFIG_LEN) { printk(KERN_ERR "kgdbts: config string too long\n"); - return -ENOSPC; + return 1; } strcpy(config, opt); - return 0; + return 1; } =20 __setup("kgdbts=3D", kgdbts_option_setup); diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index 67bb6a25fd0a..64ce3f830262 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -107,6 +107,7 @@ #define MEI_DEV_ID_ADP_S 0x7AE8 /* Alder Lake Point S */ #define MEI_DEV_ID_ADP_LP 0x7A60 /* Alder Lake Point LP */ #define MEI_DEV_ID_ADP_P 0x51E0 /* Alder Lake Point P */ +#define MEI_DEV_ID_ADP_N 0x54E0 /* Alder Lake Point N */ =20 /* * MEI HW Section @@ -120,6 +121,7 @@ #define PCI_CFG_HFS_2 0x48 #define PCI_CFG_HFS_3 0x60 # define PCI_CFG_HFS_3_FW_SKU_MSK 0x00000070 +# define PCI_CFG_HFS_3_FW_SKU_IGN 0x00000000 # define PCI_CFG_HFS_3_FW_SKU_SPS 0x00000060 #define PCI_CFG_HFS_4 0x64 #define PCI_CFG_HFS_5 0x68 diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index d3a6c0728645..fbc4c9581864 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -1405,16 +1405,16 @@ static bool mei_me_fw_type_sps_4(const struct pci_d= ev *pdev) .quirk_probe =3D mei_me_fw_type_sps_4 =20 /** - * mei_me_fw_type_sps() - check for sps sku + * mei_me_fw_type_sps_ign() - check for sps or ign sku * - * Read ME FW Status register to check for SPS Firmware. - * The SPS FW is only signaled in pci function 0 + * Read ME FW Status register to check for SPS or IGN Firmware. + * The SPS/IGN FW is only signaled in pci function 0 * * @pdev: pci device * - * Return: true in case of SPS firmware + * Return: true in case of SPS/IGN firmware */ -static bool mei_me_fw_type_sps(const struct pci_dev *pdev) +static bool mei_me_fw_type_sps_ign(const struct pci_dev *pdev) { u32 reg; u32 fw_type; @@ -1427,14 +1427,15 @@ static bool mei_me_fw_type_sps(const struct pci_dev= *pdev) =20 dev_dbg(&pdev->dev, "fw type is %d\n", fw_type); =20 - return fw_type =3D=3D PCI_CFG_HFS_3_FW_SKU_SPS; + return fw_type =3D=3D PCI_CFG_HFS_3_FW_SKU_IGN || + fw_type =3D=3D PCI_CFG_HFS_3_FW_SKU_SPS; } =20 #define MEI_CFG_KIND_ITOUCH \ .kind =3D "itouch" =20 -#define MEI_CFG_FW_SPS \ - .quirk_probe =3D mei_me_fw_type_sps +#define MEI_CFG_FW_SPS_IGN \ + .quirk_probe =3D mei_me_fw_type_sps_ign =20 #define MEI_CFG_FW_VER_SUPP \ .fw_ver_supported =3D 1 @@ -1535,7 +1536,7 @@ static const struct mei_cfg mei_me_pch12_sps_cfg =3D { MEI_CFG_PCH8_HFS, MEI_CFG_FW_VER_SUPP, MEI_CFG_DMA_128, - MEI_CFG_FW_SPS, + MEI_CFG_FW_SPS_IGN, }; =20 /* Cannon Lake itouch with quirk for SPS 5.0 and newer Firmware exclusion @@ -1545,7 +1546,7 @@ static const struct mei_cfg mei_me_pch12_itouch_sps_c= fg =3D { MEI_CFG_KIND_ITOUCH, MEI_CFG_PCH8_HFS, MEI_CFG_FW_VER_SUPP, - MEI_CFG_FW_SPS, + MEI_CFG_FW_SPS_IGN, }; =20 /* Tiger Lake and newer devices */ @@ -1562,7 +1563,7 @@ static const struct mei_cfg mei_me_pch15_sps_cfg =3D { MEI_CFG_FW_VER_SUPP, MEI_CFG_DMA_128, MEI_CFG_TRC, - MEI_CFG_FW_SPS, + MEI_CFG_FW_SPS_IGN, }; =20 /* diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index a67f4f2d33a9..0706322154cb 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -424,31 +424,26 @@ int mei_irq_read_handler(struct mei_device *dev, list_for_each_entry(cl, &dev->file_list, link) { if (mei_cl_hbm_equal(cl, mei_hdr)) { cl_dbg(dev, cl, "got a message\n"); - break; + ret =3D mei_cl_irq_read_msg(cl, mei_hdr, meta_hdr, cmpl_list); + goto reset_slots; } } =20 /* if no recipient cl was found we assume corrupted header */ - if (&cl->link =3D=3D &dev->file_list) { - /* A message for not connected fixed address clients - * should be silently discarded - * On power down client may be force cleaned, - * silently discard such messages - */ - if (hdr_is_fixed(mei_hdr) || - dev->dev_state =3D=3D MEI_DEV_POWER_DOWN) { - mei_irq_discard_msg(dev, mei_hdr, mei_hdr->length); - ret =3D 0; - goto reset_slots; - } - dev_err(dev->dev, "no destination client found 0x%08X\n", - dev->rd_msg_hdr[0]); - ret =3D -EBADMSG; - goto end; + /* A message for not connected fixed address clients + * should be silently discarded + * On power down client may be force cleaned, + * silently discard such messages + */ + if (hdr_is_fixed(mei_hdr) || + dev->dev_state =3D=3D MEI_DEV_POWER_DOWN) { + mei_irq_discard_msg(dev, mei_hdr, mei_hdr->length); + ret =3D 0; + goto reset_slots; } - - ret =3D mei_cl_irq_read_msg(cl, mei_hdr, meta_hdr, cmpl_list); - + dev_err(dev->dev, "no destination client found 0x%08X\n", dev->rd_msg_hdr= [0]); + ret =3D -EBADMSG; + goto end; =20 reset_slots: /* reset the number of slots and header */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 3a45aaf002ac..a738253dbd05 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -113,6 +113,7 @@ static const struct pci_device_id mei_me_pci_tbl[] =3D { {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_S, MEI_ME_PCH15_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_LP, MEI_ME_PCH15_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_P, MEI_ME_PCH15_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_N, MEI_ME_PCH15_CFG)}, =20 /* required last entry */ {0, } diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index f6b7a9c5bbff..5aefe05a94f6 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -15,6 +15,7 @@ #include #include #include +#include =20 #include #include @@ -34,13 +35,13 @@ static ssize_t type_show(struct device *dev, =20 switch (card->type) { case MMC_TYPE_MMC: - return sprintf(buf, "MMC\n"); + return sysfs_emit(buf, "MMC\n"); case MMC_TYPE_SD: - return sprintf(buf, "SD\n"); + return sysfs_emit(buf, "SD\n"); case MMC_TYPE_SDIO: - return sprintf(buf, "SDIO\n"); + return sysfs_emit(buf, "SDIO\n"); case MMC_TYPE_SD_COMBO: - return sprintf(buf, "SDcombo\n"); + return sysfs_emit(buf, "SDcombo\n"); default: return -EFAULT; } diff --git a/drivers/mmc/core/bus.h b/drivers/mmc/core/bus.h index 8105852c4b62..3996b191b68d 100644 --- a/drivers/mmc/core/bus.h +++ b/drivers/mmc/core/bus.h @@ -9,6 +9,7 @@ #define _MMC_CORE_BUS_H =20 #include +#include =20 struct mmc_host; struct mmc_card; @@ -17,7 +18,7 @@ struct mmc_card; static ssize_t mmc_##name##_show (struct device *dev, struct device_attrib= ute *attr, char *buf) \ { \ struct mmc_card *card =3D mmc_dev_to_card(dev); \ - return sprintf(buf, fmt, args); \ + return sysfs_emit(buf, fmt, args); \ } \ static DEVICE_ATTR(name, S_IRUGO, mmc_##name##_show, NULL) =20 diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index cf140f4ec864..d739e2b631fe 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -588,6 +588,16 @@ struct mmc_host *mmc_alloc_host(int extra, struct devi= ce *dev) =20 EXPORT_SYMBOL(mmc_alloc_host); =20 +static int mmc_validate_host_caps(struct mmc_host *host) +{ + if (host->caps & MMC_CAP_SDIO_IRQ && !host->ops->enable_sdio_irq) { + dev_warn(host->parent, "missing ->enable_sdio_irq() ops\n"); + return -EINVAL; + } + + return 0; +} + /** * mmc_add_host - initialise host hardware * @host: mmc host @@ -600,8 +610,9 @@ int mmc_add_host(struct mmc_host *host) { int err; =20 - WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) && - !host->ops->enable_sdio_irq); + err =3D mmc_validate_host_caps(host); + if (err) + return err; =20 err =3D device_add(&host->class_dev); if (err) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index b1c1716dacf0..4a590e5d268e 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -12,6 +12,7 @@ #include #include #include +#include =20 #include #include @@ -812,12 +813,11 @@ static ssize_t mmc_fwrev_show(struct device *dev, { struct mmc_card *card =3D mmc_dev_to_card(dev); =20 - if (card->ext_csd.rev < 7) { - return sprintf(buf, "0x%x\n", card->cid.fwrev); - } else { - return sprintf(buf, "0x%*phN\n", MMC_FIRMWARE_LEN, - card->ext_csd.fwrev); - } + if (card->ext_csd.rev < 7) + return sysfs_emit(buf, "0x%x\n", card->cid.fwrev); + else + return sysfs_emit(buf, "0x%*phN\n", MMC_FIRMWARE_LEN, + card->ext_csd.fwrev); } =20 static DEVICE_ATTR(fwrev, S_IRUGO, mmc_fwrev_show, NULL); @@ -830,10 +830,10 @@ static ssize_t mmc_dsr_show(struct device *dev, struct mmc_host *host =3D card->host; =20 if (card->csd.dsr_imp && host->dsr_req) - return sprintf(buf, "0x%x\n", host->dsr); + return sysfs_emit(buf, "0x%x\n", host->dsr); else /* return default DSR value */ - return sprintf(buf, "0x%x\n", 0x404); + return sysfs_emit(buf, "0x%x\n", 0x404); } =20 static DEVICE_ATTR(dsr, S_IRUGO, mmc_dsr_show, NULL); diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 44746f2edada..17e25c9dc935 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -13,6 +13,7 @@ #include #include #include +#include =20 #include #include @@ -708,18 +709,16 @@ MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr); MMC_DEV_ATTR(rca, "0x%04x\n", card->rca); =20 =20 -static ssize_t mmc_dsr_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t mmc_dsr_show(struct device *dev, struct device_attribute *a= ttr, + char *buf) { - struct mmc_card *card =3D mmc_dev_to_card(dev); - struct mmc_host *host =3D card->host; - - if (card->csd.dsr_imp && host->dsr_req) - return sprintf(buf, "0x%x\n", host->dsr); - else - /* return default DSR value */ - return sprintf(buf, "0x%x\n", 0x404); + struct mmc_card *card =3D mmc_dev_to_card(dev); + struct mmc_host *host =3D card->host; + + if (card->csd.dsr_imp && host->dsr_req) + return sysfs_emit(buf, "0x%x\n", host->dsr); + /* return default DSR value */ + return sysfs_emit(buf, "0x%x\n", 0x404); } =20 static DEVICE_ATTR(dsr, S_IRUGO, mmc_dsr_show, NULL); @@ -735,9 +734,9 @@ static ssize_t info##num##_show(struct device *dev, str= uct device_attribute *att \ if (num > card->num_info) \ return -ENODATA; \ - if (!card->info[num-1][0]) \ + if (!card->info[num - 1][0]) \ return 0; \ - return sprintf(buf, "%s\n", card->info[num-1]); \ + return sysfs_emit(buf, "%s\n", card->info[num - 1]); \ } \ static DEVICE_ATTR_RO(info##num) =20 diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 5447c47157aa..2bd9004d76d8 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -7,6 +7,7 @@ =20 #include #include +#include =20 #include #include @@ -40,9 +41,9 @@ static ssize_t info##num##_show(struct device *dev, struc= t device_attribute *att \ if (num > card->num_info) \ return -ENODATA; \ - if (!card->info[num-1][0]) \ + if (!card->info[num - 1][0]) \ return 0; \ - return sprintf(buf, "%s\n", card->info[num-1]); \ + return sysfs_emit(buf, "%s\n", card->info[num - 1]); \ } \ static DEVICE_ATTR_RO(info##num) =20 diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index fda03b35c14a..c6268c38c69e 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -14,6 +14,7 @@ #include #include #include +#include =20 #include #include @@ -35,7 +36,7 @@ field##_show(struct device *dev, struct device_attribute = *attr, char *buf) \ struct sdio_func *func; \ \ func =3D dev_to_sdio_func (dev); \ - return sprintf(buf, format_string, args); \ + return sysfs_emit(buf, format_string, args); \ } \ static DEVICE_ATTR_RO(field) =20 @@ -52,9 +53,9 @@ static ssize_t info##num##_show(struct device *dev, struc= t device_attribute *att \ if (num > func->num_info) \ return -ENODATA; \ - if (!func->info[num-1][0]) \ + if (!func->info[num - 1][0]) \ return 0; \ - return sprintf(buf, "%s\n", func->info[num-1]); \ + return sysfs_emit(buf, "%s\n", func->info[num - 1]); \ } \ static DEVICE_ATTR_RO(info##num) =20 diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 2a757c88f9d2..80de660027d8 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1375,8 +1375,12 @@ static int davinci_mmcsd_suspend(struct device *dev) static int davinci_mmcsd_resume(struct device *dev) { struct mmc_davinci_host *host =3D dev_get_drvdata(dev); + int ret; + + ret =3D clk_enable(host->clk); + if (ret) + return ret; =20 - clk_enable(host->clk); mmc_davinci_reset_ctrl(host, 0); =20 return 0; diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_= sdmmc.c index 58cfaffa3c2d..f7c384db89bf 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -1495,12 +1495,12 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform= _device *pdev) =20 realtek_init_host(host); =20 - if (pcr->rtd3_en) { - pm_runtime_set_autosuspend_delay(&pdev->dev, 5000); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_enable(&pdev->dev); - } - + pm_runtime_no_callbacks(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, 200); + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_use_autosuspend(&pdev->dev); =20 mmc_add_host(mmc); =20 @@ -1521,11 +1521,6 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform= _device *pdev) pcr->slots[RTSX_SD_CARD].card_event =3D NULL; mmc =3D host->mmc; =20 - if (pcr->rtd3_en) { - pm_runtime_dont_use_autosuspend(&pdev->dev); - pm_runtime_disable(&pdev->dev); - } - cancel_work_sync(&host->work); =20 mutex_lock(&host->host_mutex); @@ -1548,6 +1543,9 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_= device *pdev) =20 flush_work(&host->work); =20 + pm_runtime_dont_use_autosuspend(&pdev->dev); + pm_runtime_disable(&pdev->dev); + mmc_free_host(mmc); =20 dev_dbg(&(pdev->dev), diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index f654afbe8e83..b4891bb26648 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -514,26 +514,6 @@ static const struct sdhci_am654_driver_data sdhci_j721= e_4bit_drvdata =3D { .flags =3D IOMUX_PRESENT, }; =20 -static const struct sdhci_pltfm_data sdhci_am64_8bit_pdata =3D { - .ops =3D &sdhci_j721e_8bit_ops, - .quirks2 =3D SDHCI_QUIRK2_PRESET_VALUE_BROKEN, -}; - -static const struct sdhci_am654_driver_data sdhci_am64_8bit_drvdata =3D { - .pdata =3D &sdhci_am64_8bit_pdata, - .flags =3D DLL_PRESENT | DLL_CALIB, -}; - -static const struct sdhci_pltfm_data sdhci_am64_4bit_pdata =3D { - .ops =3D &sdhci_j721e_4bit_ops, - .quirks2 =3D SDHCI_QUIRK2_PRESET_VALUE_BROKEN, -}; - -static const struct sdhci_am654_driver_data sdhci_am64_4bit_drvdata =3D { - .pdata =3D &sdhci_am64_4bit_pdata, - .flags =3D IOMUX_PRESENT, -}; - static const struct soc_device_attribute sdhci_am654_devices[] =3D { { .family =3D "AM65X", .revision =3D "SR1.0", @@ -759,11 +739,11 @@ static const struct of_device_id sdhci_am654_of_match= [] =3D { }, { .compatible =3D "ti,am64-sdhci-8bit", - .data =3D &sdhci_am64_8bit_drvdata, + .data =3D &sdhci_j721e_8bit_drvdata, }, { .compatible =3D "ti,am64-sdhci-4bit", - .data =3D &sdhci_am64_4bit_drvdata, + .data =3D &sdhci_j721e_4bit_drvdata, }, { /* sentinel */ } }; diff --git a/drivers/mtd/devices/mchp23k256.c b/drivers/mtd/devices/mchp23k= 256.c index 77c872fd3d83..7d188cdff6a2 100644 --- a/drivers/mtd/devices/mchp23k256.c +++ b/drivers/mtd/devices/mchp23k256.c @@ -229,6 +229,19 @@ static const struct of_device_id mchp23k256_of_table[]= =3D { }; MODULE_DEVICE_TABLE(of, mchp23k256_of_table); =20 +static const struct spi_device_id mchp23k256_spi_ids[] =3D { + { + .name =3D "mchp23k256", + .driver_data =3D (kernel_ulong_t)&mchp23k256_caps, + }, + { + .name =3D "mchp23lcv1024", + .driver_data =3D (kernel_ulong_t)&mchp23lcv1024_caps, + }, + {} +}; +MODULE_DEVICE_TABLE(spi, mchp23k256_spi_ids); + static struct spi_driver mchp23k256_driver =3D { .driver =3D { .name =3D "mchp23k256", @@ -236,6 +249,7 @@ static struct spi_driver mchp23k256_driver =3D { }, .probe =3D mchp23k256_probe, .remove =3D mchp23k256_remove, + .id_table =3D mchp23k256_spi_ids, }; =20 module_spi_driver(mchp23k256_driver); diff --git a/drivers/mtd/devices/mchp48l640.c b/drivers/mtd/devices/mchp48l= 640.c index 99400d0fb8c1..fbd6b6bf908e 100644 --- a/drivers/mtd/devices/mchp48l640.c +++ b/drivers/mtd/devices/mchp48l640.c @@ -357,6 +357,15 @@ static const struct of_device_id mchp48l640_of_table[]= =3D { }; MODULE_DEVICE_TABLE(of, mchp48l640_of_table); =20 +static const struct spi_device_id mchp48l640_spi_ids[] =3D { + { + .name =3D "48l640", + .driver_data =3D (kernel_ulong_t)&mchp48l640_caps, + }, + {} +}; +MODULE_DEVICE_TABLE(spi, mchp48l640_spi_ids); + static struct spi_driver mchp48l640_driver =3D { .driver =3D { .name =3D "mchp48l640", @@ -364,6 +373,7 @@ static struct spi_driver mchp48l640_driver =3D { }, .probe =3D mchp48l640_probe, .remove =3D mchp48l640_remove, + .id_table =3D mchp48l640_spi_ids, }; =20 module_spi_driver(mchp48l640_driver); diff --git a/drivers/mtd/nand/onenand/generic.c b/drivers/mtd/nand/onenand/= generic.c index 8b6f4da5d720..a4b8b65fe15f 100644 --- a/drivers/mtd/nand/onenand/generic.c +++ b/drivers/mtd/nand/onenand/generic.c @@ -53,7 +53,12 @@ static int generic_onenand_probe(struct platform_device = *pdev) } =20 info->onenand.mmcontrol =3D pdata ? pdata->mmcontrol : NULL; - info->onenand.irq =3D platform_get_irq(pdev, 0); + + err =3D platform_get_irq(pdev, 0); + if (err < 0) + goto out_iounmap; + + info->onenand.irq =3D err; =20 info->mtd.dev.parent =3D &pdev->dev; info->mtd.priv =3D &info->onenand; diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nan= d/raw/atmel/nand-controller.c index f3276ee9e4fe..ddd93bc38ea6 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -2060,13 +2060,15 @@ static int atmel_nand_controller_init(struct atmel_= nand_controller *nc, nc->mck =3D of_clk_get(dev->parent->of_node, 0); if (IS_ERR(nc->mck)) { dev_err(dev, "Failed to retrieve MCK clk\n"); - return PTR_ERR(nc->mck); + ret =3D PTR_ERR(nc->mck); + goto out_release_dma; } =20 np =3D of_parse_phandle(dev->parent->of_node, "atmel,smc", 0); if (!np) { dev_err(dev, "Missing or invalid atmel,smc property\n"); - return -EINVAL; + ret =3D -EINVAL; + goto out_release_dma; } =20 nc->smc =3D syscon_node_to_regmap(np); @@ -2074,10 +2076,16 @@ static int atmel_nand_controller_init(struct atmel_= nand_controller *nc, if (IS_ERR(nc->smc)) { ret =3D PTR_ERR(nc->smc); dev_err(dev, "Could not get SMC regmap (err =3D %d)\n", ret); - return ret; + goto out_release_dma; } =20 return 0; + +out_release_dma: + if (nc->dmac) + dma_release_channel(nc->dmac); + + return ret; } =20 static int diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/= raw/gpmi-nand/gpmi-nand.c index 5eb20dfe4186..42e0aab1a00c 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -648,6 +648,7 @@ static void gpmi_nfc_compute_timings(struct gpmi_nand_d= ata *this, const struct nand_sdr_timings *sdr) { struct gpmi_nfc_hardware_timing *hw =3D &this->hw; + struct resources *r =3D &this->resources; unsigned int dll_threshold_ps =3D this->devdata->max_chain_delay; unsigned int period_ps, reference_period_ps; unsigned int data_setup_cycles, data_hold_cycles, addr_setup_cycles; @@ -671,6 +672,8 @@ static void gpmi_nfc_compute_timings(struct gpmi_nand_d= ata *this, wrn_dly_sel =3D BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY; } =20 + hw->clk_rate =3D clk_round_rate(r->clock[0], hw->clk_rate); + /* SDR core timings are given in picoseconds */ period_ps =3D div_u64((u64)NSEC_PER_SEC * 1000, hw->clk_rate); =20 diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_b= ase.c index d5a2110eb38e..881e768f636f 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -335,16 +335,19 @@ static int nand_isbad_bbm(struct nand_chip *chip, lof= f_t ofs) * * Return: -EBUSY if the chip has been suspended, 0 otherwise */ -static int nand_get_device(struct nand_chip *chip) +static void nand_get_device(struct nand_chip *chip) { - mutex_lock(&chip->lock); - if (chip->suspended) { + /* Wait until the device is resumed. */ + while (1) { + mutex_lock(&chip->lock); + if (!chip->suspended) { + mutex_lock(&chip->controller->lock); + return; + } mutex_unlock(&chip->lock); - return -EBUSY; - } - mutex_lock(&chip->controller->lock); =20 - return 0; + wait_event(chip->resume_wq, !chip->suspended); + } } =20 /** @@ -573,9 +576,7 @@ static int nand_block_markbad_lowlevel(struct nand_chip= *chip, loff_t ofs) nand_erase_nand(chip, &einfo, 0); =20 /* Write bad block marker to OOB */ - ret =3D nand_get_device(chip); - if (ret) - return ret; + nand_get_device(chip); =20 ret =3D nand_markbad_bbm(chip, ofs); nand_release_device(chip); @@ -3823,9 +3824,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t= from, ops->mode !=3D MTD_OPS_RAW) return -ENOTSUPP; =20 - ret =3D nand_get_device(chip); - if (ret) - return ret; + nand_get_device(chip); =20 if (!ops->datbuf) ret =3D nand_do_read_oob(chip, from, ops); @@ -4412,13 +4411,11 @@ static int nand_write_oob(struct mtd_info *mtd, lof= f_t to, struct mtd_oob_ops *ops) { struct nand_chip *chip =3D mtd_to_nand(mtd); - int ret; + int ret =3D 0; =20 ops->retlen =3D 0; =20 - ret =3D nand_get_device(chip); - if (ret) - return ret; + nand_get_device(chip); =20 switch (ops->mode) { case MTD_OPS_PLACE_OOB: @@ -4478,9 +4475,7 @@ int nand_erase_nand(struct nand_chip *chip, struct er= ase_info *instr, return -EIO; =20 /* Grab the lock and see if the device is available */ - ret =3D nand_get_device(chip); - if (ret) - return ret; + nand_get_device(chip); =20 /* Shift to get first page */ page =3D (int)(instr->addr >> chip->page_shift); @@ -4567,7 +4562,7 @@ static void nand_sync(struct mtd_info *mtd) pr_debug("%s: called\n", __func__); =20 /* Grab the lock and see if the device is available */ - WARN_ON(nand_get_device(chip)); + nand_get_device(chip); /* Release it and go back */ nand_release_device(chip); } @@ -4584,9 +4579,7 @@ static int nand_block_isbad(struct mtd_info *mtd, lof= f_t offs) int ret; =20 /* Select the NAND device */ - ret =3D nand_get_device(chip); - if (ret) - return ret; + nand_get_device(chip); =20 nand_select_target(chip, chipnr); =20 @@ -4657,6 +4650,8 @@ static void nand_resume(struct mtd_info *mtd) __func__); } mutex_unlock(&chip->lock); + + wake_up_all(&chip->resume_wq); } =20 /** @@ -5434,6 +5429,7 @@ static int nand_scan_ident(struct nand_chip *chip, un= signed int maxchips, chip->cur_cs =3D -1; =20 mutex_init(&chip->lock); + init_waitqueue_head(&chip->resume_wq); =20 /* Enforce the right timings for reset/detection */ chip->current_interface_config =3D nand_get_reset_interface_config(); diff --git a/drivers/mtd/nand/raw/pl35x-nand-controller.c b/drivers/mtd/nan= d/raw/pl35x-nand-controller.c index 8a91e069ee2e..3c6f6aff649f 100644 --- a/drivers/mtd/nand/raw/pl35x-nand-controller.c +++ b/drivers/mtd/nand/raw/pl35x-nand-controller.c @@ -1062,7 +1062,7 @@ static int pl35x_nand_chip_init(struct pl35x_nandc *n= fc, chip->controller =3D &nfc->controller; mtd =3D nand_to_mtd(chip); mtd->dev.parent =3D nfc->dev; - nand_set_flash_node(chip, nfc->dev->of_node); + nand_set_flash_node(chip, np); if (!mtd->name) { mtd->name =3D devm_kasprintf(nfc->dev, GFP_KERNEL, "%s", PL35X_NANDC_DRIVER_NAME); diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index a7e3eb9befb6..a32050fecabf 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -351,9 +351,6 @@ static ssize_t dev_attribute_show(struct device *dev, * we still can use 'ubi->ubi_num'. */ ubi =3D container_of(dev, struct ubi_device, dev); - ubi =3D ubi_get_device(ubi->ubi_num); - if (!ubi) - return -ENODEV; =20 if (attr =3D=3D &dev_eraseblock_size) ret =3D sprintf(buf, "%d\n", ubi->leb_size); @@ -382,7 +379,6 @@ static ssize_t dev_attribute_show(struct device *dev, else ret =3D -EINVAL; =20 - ubi_put_device(ubi); return ret; } =20 @@ -979,9 +975,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_nu= m, goto out_detach; } =20 - /* Make device "available" before it becomes accessible via sysfs */ - ubi_devices[ubi_num] =3D ubi; - err =3D uif_init(ubi); if (err) goto out_detach; @@ -1026,6 +1019,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_= num, wake_up_process(ubi->bgt_thread); spin_unlock(&ubi->wl_lock); =20 + ubi_devices[ubi_num] =3D ubi; ubi_notify_all(ubi, UBI_VOLUME_ADDED, NULL); return ubi_num; =20 @@ -1034,7 +1028,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_= num, out_uif: uif_close(ubi); out_detach: - ubi_devices[ubi_num] =3D NULL; ubi_wl_close(ubi); ubi_free_all_volumes(ubi); vfree(ubi->vtbl); diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index 022af59906aa..6b5f1ffd961b 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -468,7 +468,9 @@ static int scan_pool(struct ubi_device *ubi, struct ubi= _attach_info *ai, if (err =3D=3D UBI_IO_FF_BITFLIPS) scrub =3D 1; =20 - add_aeb(ai, free, pnum, ec, scrub); + ret =3D add_aeb(ai, free, pnum, ec, scrub); + if (ret) + goto out; continue; } else if (err =3D=3D 0 || err =3D=3D UBI_IO_BITFLIPS) { dbg_bld("Found non empty PEB:%i in pool", pnum); @@ -638,8 +640,10 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, if (fm_pos >=3D fm_size) goto fail_bad; =20 - add_aeb(ai, &ai->free, be32_to_cpu(fmec->pnum), - be32_to_cpu(fmec->ec), 0); + ret =3D add_aeb(ai, &ai->free, be32_to_cpu(fmec->pnum), + be32_to_cpu(fmec->ec), 0); + if (ret) + goto fail; } =20 /* read EC values from used list */ @@ -649,8 +653,10 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, if (fm_pos >=3D fm_size) goto fail_bad; =20 - add_aeb(ai, &used, be32_to_cpu(fmec->pnum), - be32_to_cpu(fmec->ec), 0); + ret =3D add_aeb(ai, &used, be32_to_cpu(fmec->pnum), + be32_to_cpu(fmec->ec), 0); + if (ret) + goto fail; } =20 /* read EC values from scrub list */ @@ -660,8 +666,10 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, if (fm_pos >=3D fm_size) goto fail_bad; =20 - add_aeb(ai, &used, be32_to_cpu(fmec->pnum), - be32_to_cpu(fmec->ec), 1); + ret =3D add_aeb(ai, &used, be32_to_cpu(fmec->pnum), + be32_to_cpu(fmec->ec), 1); + if (ret) + goto fail; } =20 /* read EC values from erase list */ @@ -671,8 +679,10 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, if (fm_pos >=3D fm_size) goto fail_bad; =20 - add_aeb(ai, &ai->erase, be32_to_cpu(fmec->pnum), - be32_to_cpu(fmec->ec), 1); + ret =3D add_aeb(ai, &ai->erase, be32_to_cpu(fmec->pnum), + be32_to_cpu(fmec->ec), 1); + if (ret) + goto fail; } =20 ai->mean_ec =3D div_u64(ai->ec_sum, ai->ec_count); diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 139ee132bfbc..1bc7b3a05604 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -56,16 +56,11 @@ static ssize_t vol_attribute_show(struct device *dev, { int ret; struct ubi_volume *vol =3D container_of(dev, struct ubi_volume, dev); - struct ubi_device *ubi; - - ubi =3D ubi_get_device(vol->ubi->ubi_num); - if (!ubi) - return -ENODEV; + struct ubi_device *ubi =3D vol->ubi; =20 spin_lock(&ubi->volumes_lock); if (!ubi->volumes[vol->vol_id]) { spin_unlock(&ubi->volumes_lock); - ubi_put_device(ubi); return -ENODEV; } /* Take a reference to prevent volume removal */ @@ -103,7 +98,6 @@ static ssize_t vol_attribute_show(struct device *dev, vol->ref_count -=3D 1; ubi_assert(vol->ref_count >=3D 0); spin_unlock(&ubi->volumes_lock); - ubi_put_device(ubi); return ret; } =20 diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c index edffc3489a12..a7d79100b685 100644 --- a/drivers/net/bareudp.c +++ b/drivers/net/bareudp.c @@ -141,14 +141,14 @@ static int bareudp_udp_encap_recv(struct sock *sk, st= ruct sk_buff *skb) skb_reset_network_header(skb); skb_reset_mac_header(skb); =20 - if (!IS_ENABLED(CONFIG_IPV6) || family =3D=3D AF_INET) + if (!ipv6_mod_enabled() || family =3D=3D AF_INET) err =3D IP_ECN_decapsulate(oiph, skb); else err =3D IP6_ECN_decapsulate(oiph, skb); =20 if (unlikely(err)) { if (log_ecn_error) { - if (!IS_ENABLED(CONFIG_IPV6) || family =3D=3D AF_INET) + if (!ipv6_mod_enabled() || family =3D=3D AF_INET) net_info_ratelimited("non-ECT from %pI4 " "with TOS=3D%#x\n", &((struct iphdr *)oiph)->saddr, @@ -214,11 +214,12 @@ static struct socket *bareudp_create_sock(struct net = *net, __be16 port) int err; =20 memset(&udp_conf, 0, sizeof(udp_conf)); -#if IS_ENABLED(CONFIG_IPV6) - udp_conf.family =3D AF_INET6; -#else - udp_conf.family =3D AF_INET; -#endif + + if (ipv6_mod_enabled()) + udp_conf.family =3D AF_INET6; + else + udp_conf.family =3D AF_INET; + udp_conf.local_udp_port =3D port; /* Open UDP socket */ err =3D udp_sock_create(net, &udp_conf, &sock); @@ -441,7 +442,7 @@ static netdev_tx_t bareudp_xmit(struct sk_buff *skb, st= ruct net_device *dev) } =20 rcu_read_lock(); - if (IS_ENABLED(CONFIG_IPV6) && info->mode & IP_TUNNEL_INFO_IPV6) + if (ipv6_mod_enabled() && info->mode & IP_TUNNEL_INFO_IPV6) err =3D bareudp6_xmit_skb(skb, dev, bareudp, info); else err =3D bareudp_xmit_skb(skb, dev, bareudp, info); @@ -471,7 +472,7 @@ static int bareudp_fill_metadata_dst(struct net_device = *dev, =20 use_cache =3D ip_tunnel_dst_cache_usable(skb, info); =20 - if (!IS_ENABLED(CONFIG_IPV6) || ip_tunnel_info_af(info) =3D=3D AF_INET) { + if (!ipv6_mod_enabled() || ip_tunnel_info_af(info) =3D=3D AF_INET) { struct rtable *rt; __be32 saddr; =20 diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 755f4a59f784..915cfd71f7bf 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -1633,8 +1633,6 @@ static netdev_tx_t m_can_tx_handler(struct m_can_clas= sdev *cdev) if (err) goto out_fail; =20 - can_put_echo_skb(skb, dev, 0, 0); - if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) { cccr =3D m_can_read(cdev, M_CAN_CCCR); cccr &=3D ~CCCR_CMR_MASK; @@ -1651,6 +1649,9 @@ static netdev_tx_t m_can_tx_handler(struct m_can_clas= sdev *cdev) m_can_write(cdev, M_CAN_CCCR, cccr); } m_can_write(cdev, M_CAN_TXBTIE, 0x1); + + can_put_echo_skb(skb, dev, 0, 0); + m_can_write(cdev, M_CAN_TXBAR, 0x1); /* End of xmit function for version 3.0.x */ } else { diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/c= an/spi/mcp251xfd/mcp251xfd-core.c index 9a4791d88683..3a0f022b1562 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c @@ -2706,7 +2706,7 @@ mcp251xfd_register_get_dev_id(const struct mcp251xfd_= priv *priv, out_kfree_buf_rx: kfree(buf_rx); =20 - return 0; + return err; } =20 #define MCP251XFD_QUIRK_ACTIVE(quirk) \ diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index 7cf65936d02e..ccbe606dc400 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -821,7 +821,6 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *s= kb, struct net_device *ne =20 usb_unanchor_urb(urb); usb_free_coherent(dev->udev, size, buf, urb->transfer_dma); - dev_kfree_skb(skb); =20 atomic_dec(&dev->active_tx_urbs); =20 diff --git a/drivers/net/can/usb/mcba_usb.c b/drivers/net/can/usb/mcba_usb.c index a1a154c08b7f..023bd34d48e3 100644 --- a/drivers/net/can/usb/mcba_usb.c +++ b/drivers/net/can/usb/mcba_usb.c @@ -33,10 +33,6 @@ #define MCBA_USB_RX_BUFF_SIZE 64 #define MCBA_USB_TX_BUFF_SIZE (sizeof(struct mcba_usb_msg)) =20 -/* MCBA endpoint numbers */ -#define MCBA_USB_EP_IN 1 -#define MCBA_USB_EP_OUT 1 - /* Microchip command id */ #define MBCA_CMD_RECEIVE_MESSAGE 0xE3 #define MBCA_CMD_I_AM_ALIVE_FROM_CAN 0xF5 @@ -84,6 +80,8 @@ struct mcba_priv { atomic_t free_ctx_cnt; void *rxbuf[MCBA_MAX_RX_URBS]; dma_addr_t rxbuf_dma[MCBA_MAX_RX_URBS]; + int rx_pipe; + int tx_pipe; }; =20 /* CAN frame */ @@ -272,10 +270,8 @@ static netdev_tx_t mcba_usb_xmit(struct mcba_priv *pri= v, =20 memcpy(buf, usb_msg, MCBA_USB_TX_BUFF_SIZE); =20 - usb_fill_bulk_urb(urb, priv->udev, - usb_sndbulkpipe(priv->udev, MCBA_USB_EP_OUT), buf, - MCBA_USB_TX_BUFF_SIZE, mcba_usb_write_bulk_callback, - ctx); + usb_fill_bulk_urb(urb, priv->udev, priv->tx_pipe, buf, MCBA_USB_TX_BUFF_S= IZE, + mcba_usb_write_bulk_callback, ctx); =20 urb->transfer_flags |=3D URB_NO_TRANSFER_DMA_MAP; usb_anchor_urb(urb, &priv->tx_submitted); @@ -368,7 +364,6 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *= skb, xmit_failed: can_free_echo_skb(priv->netdev, ctx->ndx, NULL); mcba_usb_free_ctx(ctx); - dev_kfree_skb(skb); stats->tx_dropped++; =20 return NETDEV_TX_OK; @@ -611,7 +606,7 @@ static void mcba_usb_read_bulk_callback(struct urb *urb) resubmit_urb: =20 usb_fill_bulk_urb(urb, priv->udev, - usb_rcvbulkpipe(priv->udev, MCBA_USB_EP_OUT), + priv->rx_pipe, urb->transfer_buffer, MCBA_USB_RX_BUFF_SIZE, mcba_usb_read_bulk_callback, priv); =20 @@ -656,7 +651,7 @@ static int mcba_usb_start(struct mcba_priv *priv) urb->transfer_dma =3D buf_dma; =20 usb_fill_bulk_urb(urb, priv->udev, - usb_rcvbulkpipe(priv->udev, MCBA_USB_EP_IN), + priv->rx_pipe, buf, MCBA_USB_RX_BUFF_SIZE, mcba_usb_read_bulk_callback, priv); urb->transfer_flags |=3D URB_NO_TRANSFER_DMA_MAP; @@ -810,6 +805,13 @@ static int mcba_usb_probe(struct usb_interface *intf, struct mcba_priv *priv; int err; struct usb_device *usbdev =3D interface_to_usbdev(intf); + struct usb_endpoint_descriptor *in, *out; + + err =3D usb_find_common_endpoints(intf->cur_altsetting, &in, &out, NULL, = NULL); + if (err) { + dev_err(&intf->dev, "Can't find endpoints\n"); + return err; + } =20 netdev =3D alloc_candev(sizeof(struct mcba_priv), MCBA_MAX_TX_URBS); if (!netdev) { @@ -855,6 +857,9 @@ static int mcba_usb_probe(struct usb_interface *intf, goto cleanup_free_candev; } =20 + priv->rx_pipe =3D usb_rcvbulkpipe(priv->udev, in->bEndpointAddress); + priv->tx_pipe =3D usb_sndbulkpipe(priv->udev, out->bEndpointAddress); + devm_can_led_init(netdev); =20 /* Start USB dev only if we have successfully registered CAN device */ diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c index 040324362b26..614a342114e2 100644 --- a/drivers/net/can/usb/usb_8dev.c +++ b/drivers/net/can/usb/usb_8dev.c @@ -668,9 +668,20 @@ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff = *skb, atomic_inc(&priv->active_tx_urbs); =20 err =3D usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err)) - goto failed; - else if (atomic_read(&priv->active_tx_urbs) >=3D MAX_TX_URBS) + if (unlikely(err)) { + can_free_echo_skb(netdev, context->echo_index, NULL); + + usb_unanchor_urb(urb); + usb_free_coherent(priv->udev, size, buf, urb->transfer_dma); + + atomic_dec(&priv->active_tx_urbs); + + if (err =3D=3D -ENODEV) + netif_device_detach(netdev); + else + netdev_warn(netdev, "failed tx_urb %d\n", err); + stats->tx_dropped++; + } else if (atomic_read(&priv->active_tx_urbs) >=3D MAX_TX_URBS) /* Slow down tx path */ netif_stop_queue(netdev); =20 @@ -689,19 +700,6 @@ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff = *skb, =20 return NETDEV_TX_BUSY; =20 -failed: - can_free_echo_skb(netdev, context->echo_index, NULL); - - usb_unanchor_urb(urb); - usb_free_coherent(priv->udev, size, buf, urb->transfer_dma); - - atomic_dec(&priv->active_tx_urbs); - - if (err =3D=3D -ENODEV) - netif_device_detach(netdev); - else - netdev_warn(netdev, "failed tx_urb %d\n", err); - nomembuf: usb_free_urb(urb); =20 diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index 8861a7d875e7..be5566168d0f 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c @@ -148,7 +148,7 @@ static void vxcan_setup(struct net_device *dev) dev->hard_header_len =3D 0; dev->addr_len =3D 0; dev->tx_queue_len =3D 0; - dev->flags =3D (IFF_NOARP|IFF_ECHO); + dev->flags =3D IFF_NOARP; dev->netdev_ops =3D &vxcan_netdev_ops; dev->needs_free_netdev =3D true; =20 diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index 0029d279616f..37a3dabdce31 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -68,17 +68,7 @@ config NET_DSA_QCA8K This enables support for the Qualcomm Atheros QCA8K Ethernet switch chips. =20 -config NET_DSA_REALTEK_SMI - tristate "Realtek SMI Ethernet switch family support" - select NET_DSA_TAG_RTL4_A - select NET_DSA_TAG_RTL8_4 - select FIXED_PHY - select IRQ_DOMAIN - select REALTEK_PHY - select REGMAP - help - This enables support for the Realtek SMI-based switch - chips, currently only RTL8366RB. +source "drivers/net/dsa/realtek/Kconfig" =20 config NET_DSA_SMSC_LAN9303 tristate diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile index 8da1569a34e6..e73838c12256 100644 --- a/drivers/net/dsa/Makefile +++ b/drivers/net/dsa/Makefile @@ -9,8 +9,6 @@ obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) +=3D lantiq_gswip.o obj-$(CONFIG_NET_DSA_MT7530) +=3D mt7530.o obj-$(CONFIG_NET_DSA_MV88E6060) +=3D mv88e6060.o obj-$(CONFIG_NET_DSA_QCA8K) +=3D qca8k.o -obj-$(CONFIG_NET_DSA_REALTEK_SMI) +=3D realtek-smi.o -realtek-smi-objs :=3D realtek-smi-core.o rtl8366.o rtl8366rb.o rtl8365mb.o obj-$(CONFIG_NET_DSA_SMSC_LAN9303) +=3D lan9303-core.o obj-$(CONFIG_NET_DSA_SMSC_LAN9303_I2C) +=3D lan9303_i2c.o obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) +=3D lan9303_mdio.o @@ -23,5 +21,6 @@ obj-y +=3D microchip/ obj-y +=3D mv88e6xxx/ obj-y +=3D ocelot/ obj-y +=3D qca/ +obj-y +=3D realtek/ obj-y +=3D sja1105/ obj-y +=3D xrs700x/ diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c index a7e2fcf2df2c..edbe5e7f1cb6 100644 --- a/drivers/net/dsa/bcm_sf2_cfp.c +++ b/drivers/net/dsa/bcm_sf2_cfp.c @@ -567,14 +567,14 @@ static void bcm_sf2_cfp_slice_ipv6(struct bcm_sf2_pri= v *priv, static struct cfp_rule *bcm_sf2_cfp_rule_find(struct bcm_sf2_priv *priv, int port, u32 location) { - struct cfp_rule *rule =3D NULL; + struct cfp_rule *rule; =20 list_for_each_entry(rule, &priv->cfp.rules_list, next) { if (rule->port =3D=3D port && rule->fs.location =3D=3D location) - break; + return rule; } =20 - return rule; + return NULL; } =20 static int bcm_sf2_cfp_rule_cmp(struct bcm_sf2_priv *priv, int port, diff --git a/drivers/net/dsa/microchip/ksz8795_spi.c b/drivers/net/dsa/micr= ochip/ksz8795_spi.c index 866767b70d65..b0a7dee27ffc 100644 --- a/drivers/net/dsa/microchip/ksz8795_spi.c +++ b/drivers/net/dsa/microchip/ksz8795_spi.c @@ -124,12 +124,23 @@ static const struct of_device_id ksz8795_dt_ids[] =3D= { }; MODULE_DEVICE_TABLE(of, ksz8795_dt_ids); =20 +static const struct spi_device_id ksz8795_spi_ids[] =3D { + { "ksz8765" }, + { "ksz8794" }, + { "ksz8795" }, + { "ksz8863" }, + { "ksz8873" }, + { }, +}; +MODULE_DEVICE_TABLE(spi, ksz8795_spi_ids); + static struct spi_driver ksz8795_spi_driver =3D { .driver =3D { .name =3D "ksz8795-switch", .owner =3D THIS_MODULE, .of_match_table =3D of_match_ptr(ksz8795_dt_ids), }, + .id_table =3D ksz8795_spi_ids, .probe =3D ksz8795_spi_probe, .remove =3D ksz8795_spi_remove, .shutdown =3D ksz8795_spi_shutdown, diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/micr= ochip/ksz9477_spi.c index e3cb0e6c9f6f..43addeabfc25 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -98,12 +98,24 @@ static const struct of_device_id ksz9477_dt_ids[] =3D { }; MODULE_DEVICE_TABLE(of, ksz9477_dt_ids); =20 +static const struct spi_device_id ksz9477_spi_ids[] =3D { + { "ksz9477" }, + { "ksz9897" }, + { "ksz9893" }, + { "ksz9563" }, + { "ksz8563" }, + { "ksz9567" }, + { }, +}; +MODULE_DEVICE_TABLE(spi, ksz9477_spi_ids); + static struct spi_driver ksz9477_spi_driver =3D { .driver =3D { .name =3D "ksz9477-switch", .owner =3D THIS_MODULE, .of_match_table =3D of_match_ptr(ksz9477_dt_ids), }, + .id_table =3D ksz9477_spi_ids, .probe =3D ksz9477_spi_probe, .remove =3D ksz9477_spi_remove, .shutdown =3D ksz9477_spi_shutdown, diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/c= hip.c index ec8b02f5459d..b420e0ef46e3 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3655,6 +3655,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops =3D { .port_sync_link =3D mv88e6185_port_sync_link, .port_set_speed_duplex =3D mv88e6185_port_set_speed_duplex, .port_tag_remap =3D mv88e6095_port_tag_remap, + .port_set_policy =3D mv88e6352_port_set_policy, .port_set_frame_mode =3D mv88e6351_port_set_frame_mode, .port_set_ucast_flood =3D mv88e6352_port_set_ucast_flood, .port_set_mcast_flood =3D mv88e6352_port_set_mcast_flood, diff --git a/drivers/net/dsa/realtek-smi-core.c b/drivers/net/dsa/realtek-s= mi-core.c deleted file mode 100644 index c66ebd0ee217..000000000000 --- a/drivers/net/dsa/realtek-smi-core.c +++ /dev/null @@ -1,523 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* Realtek Simple Management Interface (SMI) driver - * It can be discussed how "simple" this interface is. - * - * The SMI protocol piggy-backs the MDIO MDC and MDIO signals levels - * but the protocol is not MDIO at all. Instead it is a Realtek - * pecularity that need to bit-bang the lines in a special way to - * communicate with the switch. - * - * ASICs we intend to support with this driver: - * - * RTL8366 - The original version, apparently - * RTL8369 - Similar enough to have the same datsheet as RTL8366 - * RTL8366RB - Probably reads out "RTL8366 revision B", has a quite - * different register layout from the other two - * RTL8366S - Is this "RTL8366 super"? - * RTL8367 - Has an OpenWRT driver as well - * RTL8368S - Seems to be an alternative name for RTL8366RB - * RTL8370 - Also uses SMI - * - * Copyright (C) 2017 Linus Walleij - * Copyright (C) 2010 Antti Sepp=C3=A4l=C3=A4 - * Copyright (C) 2010 Roman Yeryomin - * Copyright (C) 2011 Colin Leitner - * Copyright (C) 2009-2010 Gabor Juhos - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "realtek-smi-core.h" - -#define REALTEK_SMI_ACK_RETRY_COUNT 5 -#define REALTEK_SMI_HW_STOP_DELAY 25 /* msecs */ -#define REALTEK_SMI_HW_START_DELAY 100 /* msecs */ - -static inline void realtek_smi_clk_delay(struct realtek_smi *smi) -{ - ndelay(smi->clk_delay); -} - -static void realtek_smi_start(struct realtek_smi *smi) -{ - /* Set GPIO pins to output mode, with initial state: - * SCK =3D 0, SDA =3D 1 - */ - gpiod_direction_output(smi->mdc, 0); - gpiod_direction_output(smi->mdio, 1); - realtek_smi_clk_delay(smi); - - /* CLK 1: 0 -> 1, 1 -> 0 */ - gpiod_set_value(smi->mdc, 1); - realtek_smi_clk_delay(smi); - gpiod_set_value(smi->mdc, 0); - realtek_smi_clk_delay(smi); - - /* CLK 2: */ - gpiod_set_value(smi->mdc, 1); - realtek_smi_clk_delay(smi); - gpiod_set_value(smi->mdio, 0); - realtek_smi_clk_delay(smi); - gpiod_set_value(smi->mdc, 0); - realtek_smi_clk_delay(smi); - gpiod_set_value(smi->mdio, 1); -} - -static void realtek_smi_stop(struct realtek_smi *smi) -{ - realtek_smi_clk_delay(smi); - gpiod_set_value(smi->mdio, 0); - gpiod_set_value(smi->mdc, 1); - realtek_smi_clk_delay(smi); - gpiod_set_value(smi->mdio, 1); - realtek_smi_clk_delay(smi); - gpiod_set_value(smi->mdc, 1); - realtek_smi_clk_delay(smi); - gpiod_set_value(smi->mdc, 0); - realtek_smi_clk_delay(smi); - gpiod_set_value(smi->mdc, 1); - - /* Add a click */ - realtek_smi_clk_delay(smi); - gpiod_set_value(smi->mdc, 0); - realtek_smi_clk_delay(smi); - gpiod_set_value(smi->mdc, 1); - - /* Set GPIO pins to input mode */ - gpiod_direction_input(smi->mdio); - gpiod_direction_input(smi->mdc); -} - -static void realtek_smi_write_bits(struct realtek_smi *smi, u32 data, u32 = len) -{ - for (; len > 0; len--) { - realtek_smi_clk_delay(smi); - - /* Prepare data */ - gpiod_set_value(smi->mdio, !!(data & (1 << (len - 1)))); - realtek_smi_clk_delay(smi); - - /* Clocking */ - gpiod_set_value(smi->mdc, 1); - realtek_smi_clk_delay(smi); - gpiod_set_value(smi->mdc, 0); - } -} - -static void realtek_smi_read_bits(struct realtek_smi *smi, u32 len, u32 *d= ata) -{ - gpiod_direction_input(smi->mdio); - - for (*data =3D 0; len > 0; len--) { - u32 u; - - realtek_smi_clk_delay(smi); - - /* Clocking */ - gpiod_set_value(smi->mdc, 1); - realtek_smi_clk_delay(smi); - u =3D !!gpiod_get_value(smi->mdio); - gpiod_set_value(smi->mdc, 0); - - *data |=3D (u << (len - 1)); - } - - gpiod_direction_output(smi->mdio, 0); -} - -static int realtek_smi_wait_for_ack(struct realtek_smi *smi) -{ - int retry_cnt; - - retry_cnt =3D 0; - do { - u32 ack; - - realtek_smi_read_bits(smi, 1, &ack); - if (ack =3D=3D 0) - break; - - if (++retry_cnt > REALTEK_SMI_ACK_RETRY_COUNT) { - dev_err(smi->dev, "ACK timeout\n"); - return -ETIMEDOUT; - } - } while (1); - - return 0; -} - -static int realtek_smi_write_byte(struct realtek_smi *smi, u8 data) -{ - realtek_smi_write_bits(smi, data, 8); - return realtek_smi_wait_for_ack(smi); -} - -static int realtek_smi_write_byte_noack(struct realtek_smi *smi, u8 data) -{ - realtek_smi_write_bits(smi, data, 8); - return 0; -} - -static int realtek_smi_read_byte0(struct realtek_smi *smi, u8 *data) -{ - u32 t; - - /* Read data */ - realtek_smi_read_bits(smi, 8, &t); - *data =3D (t & 0xff); - - /* Send an ACK */ - realtek_smi_write_bits(smi, 0x00, 1); - - return 0; -} - -static int realtek_smi_read_byte1(struct realtek_smi *smi, u8 *data) -{ - u32 t; - - /* Read data */ - realtek_smi_read_bits(smi, 8, &t); - *data =3D (t & 0xff); - - /* Send an ACK */ - realtek_smi_write_bits(smi, 0x01, 1); - - return 0; -} - -static int realtek_smi_read_reg(struct realtek_smi *smi, u32 addr, u32 *da= ta) -{ - unsigned long flags; - u8 lo =3D 0; - u8 hi =3D 0; - int ret; - - spin_lock_irqsave(&smi->lock, flags); - - realtek_smi_start(smi); - - /* Send READ command */ - ret =3D realtek_smi_write_byte(smi, smi->cmd_read); - if (ret) - goto out; - - /* Set ADDR[7:0] */ - ret =3D realtek_smi_write_byte(smi, addr & 0xff); - if (ret) - goto out; - - /* Set ADDR[15:8] */ - ret =3D realtek_smi_write_byte(smi, addr >> 8); - if (ret) - goto out; - - /* Read DATA[7:0] */ - realtek_smi_read_byte0(smi, &lo); - /* Read DATA[15:8] */ - realtek_smi_read_byte1(smi, &hi); - - *data =3D ((u32)lo) | (((u32)hi) << 8); - - ret =3D 0; - - out: - realtek_smi_stop(smi); - spin_unlock_irqrestore(&smi->lock, flags); - - return ret; -} - -static int realtek_smi_write_reg(struct realtek_smi *smi, - u32 addr, u32 data, bool ack) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&smi->lock, flags); - - realtek_smi_start(smi); - - /* Send WRITE command */ - ret =3D realtek_smi_write_byte(smi, smi->cmd_write); - if (ret) - goto out; - - /* Set ADDR[7:0] */ - ret =3D realtek_smi_write_byte(smi, addr & 0xff); - if (ret) - goto out; - - /* Set ADDR[15:8] */ - ret =3D realtek_smi_write_byte(smi, addr >> 8); - if (ret) - goto out; - - /* Write DATA[7:0] */ - ret =3D realtek_smi_write_byte(smi, data & 0xff); - if (ret) - goto out; - - /* Write DATA[15:8] */ - if (ack) - ret =3D realtek_smi_write_byte(smi, data >> 8); - else - ret =3D realtek_smi_write_byte_noack(smi, data >> 8); - if (ret) - goto out; - - ret =3D 0; - - out: - realtek_smi_stop(smi); - spin_unlock_irqrestore(&smi->lock, flags); - - return ret; -} - -/* There is one single case when we need to use this accessor and that - * is when issueing soft reset. Since the device reset as soon as we write - * that bit, no ACK will come back for natural reasons. - */ -int realtek_smi_write_reg_noack(struct realtek_smi *smi, u32 addr, - u32 data) -{ - return realtek_smi_write_reg(smi, addr, data, false); -} -EXPORT_SYMBOL_GPL(realtek_smi_write_reg_noack); - -/* Regmap accessors */ - -static int realtek_smi_write(void *ctx, u32 reg, u32 val) -{ - struct realtek_smi *smi =3D ctx; - - return realtek_smi_write_reg(smi, reg, val, true); -} - -static int realtek_smi_read(void *ctx, u32 reg, u32 *val) -{ - struct realtek_smi *smi =3D ctx; - - return realtek_smi_read_reg(smi, reg, val); -} - -static const struct regmap_config realtek_smi_mdio_regmap_config =3D { - .reg_bits =3D 10, /* A4..A0 R4..R0 */ - .val_bits =3D 16, - .reg_stride =3D 1, - /* PHY regs are at 0x8000 */ - .max_register =3D 0xffff, - .reg_format_endian =3D REGMAP_ENDIAN_BIG, - .reg_read =3D realtek_smi_read, - .reg_write =3D realtek_smi_write, - .cache_type =3D REGCACHE_NONE, -}; - -static int realtek_smi_mdio_read(struct mii_bus *bus, int addr, int regnum) -{ - struct realtek_smi *smi =3D bus->priv; - - return smi->ops->phy_read(smi, addr, regnum); -} - -static int realtek_smi_mdio_write(struct mii_bus *bus, int addr, int regnu= m, - u16 val) -{ - struct realtek_smi *smi =3D bus->priv; - - return smi->ops->phy_write(smi, addr, regnum, val); -} - -int realtek_smi_setup_mdio(struct realtek_smi *smi) -{ - struct device_node *mdio_np; - int ret; - - mdio_np =3D of_get_compatible_child(smi->dev->of_node, "realtek,smi-mdio"= ); - if (!mdio_np) { - dev_err(smi->dev, "no MDIO bus node\n"); - return -ENODEV; - } - - smi->slave_mii_bus =3D devm_mdiobus_alloc(smi->dev); - if (!smi->slave_mii_bus) { - ret =3D -ENOMEM; - goto err_put_node; - } - smi->slave_mii_bus->priv =3D smi; - smi->slave_mii_bus->name =3D "SMI slave MII"; - smi->slave_mii_bus->read =3D realtek_smi_mdio_read; - smi->slave_mii_bus->write =3D realtek_smi_mdio_write; - snprintf(smi->slave_mii_bus->id, MII_BUS_ID_SIZE, "SMI-%d", - smi->ds->index); - smi->slave_mii_bus->dev.of_node =3D mdio_np; - smi->slave_mii_bus->parent =3D smi->dev; - smi->ds->slave_mii_bus =3D smi->slave_mii_bus; - - ret =3D devm_of_mdiobus_register(smi->dev, smi->slave_mii_bus, mdio_np); - if (ret) { - dev_err(smi->dev, "unable to register MDIO bus %s\n", - smi->slave_mii_bus->id); - goto err_put_node; - } - - return 0; - -err_put_node: - of_node_put(mdio_np); - - return ret; -} - -static int realtek_smi_probe(struct platform_device *pdev) -{ - const struct realtek_smi_variant *var; - struct device *dev =3D &pdev->dev; - struct realtek_smi *smi; - struct device_node *np; - int ret; - - var =3D of_device_get_match_data(dev); - np =3D dev->of_node; - - smi =3D devm_kzalloc(dev, sizeof(*smi) + var->chip_data_sz, GFP_KERNEL); - if (!smi) - return -ENOMEM; - smi->chip_data =3D (void *)smi + sizeof(*smi); - smi->map =3D devm_regmap_init(dev, NULL, smi, - &realtek_smi_mdio_regmap_config); - if (IS_ERR(smi->map)) { - ret =3D PTR_ERR(smi->map); - dev_err(dev, "regmap init failed: %d\n", ret); - return ret; - } - - /* Link forward and backward */ - smi->dev =3D dev; - smi->clk_delay =3D var->clk_delay; - smi->cmd_read =3D var->cmd_read; - smi->cmd_write =3D var->cmd_write; - smi->ops =3D var->ops; - - dev_set_drvdata(dev, smi); - spin_lock_init(&smi->lock); - - /* TODO: if power is software controlled, set up any regulators here */ - - /* Assert then deassert RESET */ - smi->reset =3D devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(smi->reset)) { - dev_err(dev, "failed to get RESET GPIO\n"); - return PTR_ERR(smi->reset); - } - msleep(REALTEK_SMI_HW_STOP_DELAY); - gpiod_set_value(smi->reset, 0); - msleep(REALTEK_SMI_HW_START_DELAY); - dev_info(dev, "deasserted RESET\n"); - - /* Fetch MDIO pins */ - smi->mdc =3D devm_gpiod_get_optional(dev, "mdc", GPIOD_OUT_LOW); - if (IS_ERR(smi->mdc)) - return PTR_ERR(smi->mdc); - smi->mdio =3D devm_gpiod_get_optional(dev, "mdio", GPIOD_OUT_LOW); - if (IS_ERR(smi->mdio)) - return PTR_ERR(smi->mdio); - - smi->leds_disabled =3D of_property_read_bool(np, "realtek,disable-leds"); - - ret =3D smi->ops->detect(smi); - if (ret) { - dev_err(dev, "unable to detect switch\n"); - return ret; - } - - smi->ds =3D devm_kzalloc(dev, sizeof(*smi->ds), GFP_KERNEL); - if (!smi->ds) - return -ENOMEM; - - smi->ds->dev =3D dev; - smi->ds->num_ports =3D smi->num_ports; - smi->ds->priv =3D smi; - - smi->ds->ops =3D var->ds_ops; - ret =3D dsa_register_switch(smi->ds); - if (ret) { - dev_err(dev, "unable to register switch ret =3D %d\n", ret); - return ret; - } - return 0; -} - -static int realtek_smi_remove(struct platform_device *pdev) -{ - struct realtek_smi *smi =3D platform_get_drvdata(pdev); - - if (!smi) - return 0; - - dsa_unregister_switch(smi->ds); - if (smi->slave_mii_bus) - of_node_put(smi->slave_mii_bus->dev.of_node); - gpiod_set_value(smi->reset, 1); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - -static void realtek_smi_shutdown(struct platform_device *pdev) -{ - struct realtek_smi *smi =3D platform_get_drvdata(pdev); - - if (!smi) - return; - - dsa_switch_shutdown(smi->ds); - - platform_set_drvdata(pdev, NULL); -} - -static const struct of_device_id realtek_smi_of_match[] =3D { - { - .compatible =3D "realtek,rtl8366rb", - .data =3D &rtl8366rb_variant, - }, - { - /* FIXME: add support for RTL8366S and more */ - .compatible =3D "realtek,rtl8366s", - .data =3D NULL, - }, - { - .compatible =3D "realtek,rtl8365mb", - .data =3D &rtl8365mb_variant, - }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, realtek_smi_of_match); - -static struct platform_driver realtek_smi_driver =3D { - .driver =3D { - .name =3D "realtek-smi", - .of_match_table =3D of_match_ptr(realtek_smi_of_match), - }, - .probe =3D realtek_smi_probe, - .remove =3D realtek_smi_remove, - .shutdown =3D realtek_smi_shutdown, -}; -module_platform_driver(realtek_smi_driver); - -MODULE_LICENSE("GPL"); diff --git a/drivers/net/dsa/realtek-smi-core.h b/drivers/net/dsa/realtek-s= mi-core.h deleted file mode 100644 index 5bfa53e2480a..000000000000 --- a/drivers/net/dsa/realtek-smi-core.h +++ /dev/null @@ -1,145 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* Realtek SMI interface driver defines - * - * Copyright (C) 2017 Linus Walleij - * Copyright (C) 2009-2010 Gabor Juhos - */ - -#ifndef _REALTEK_SMI_H -#define _REALTEK_SMI_H - -#include -#include -#include -#include - -struct realtek_smi_ops; -struct dentry; -struct inode; -struct file; - -struct rtl8366_mib_counter { - unsigned int base; - unsigned int offset; - unsigned int length; - const char *name; -}; - -/** - * struct rtl8366_vlan_mc - Virtual LAN member configuration - */ -struct rtl8366_vlan_mc { - u16 vid; - u16 untag; - u16 member; - u8 fid; - u8 priority; -}; - -struct rtl8366_vlan_4k { - u16 vid; - u16 untag; - u16 member; - u8 fid; -}; - -struct realtek_smi { - struct device *dev; - struct gpio_desc *reset; - struct gpio_desc *mdc; - struct gpio_desc *mdio; - struct regmap *map; - struct mii_bus *slave_mii_bus; - - unsigned int clk_delay; - u8 cmd_read; - u8 cmd_write; - spinlock_t lock; /* Locks around command writes */ - struct dsa_switch *ds; - struct irq_domain *irqdomain; - bool leds_disabled; - - unsigned int cpu_port; - unsigned int num_ports; - unsigned int num_vlan_mc; - unsigned int num_mib_counters; - struct rtl8366_mib_counter *mib_counters; - - const struct realtek_smi_ops *ops; - - int vlan_enabled; - int vlan4k_enabled; - - char buf[4096]; - void *chip_data; /* Per-chip extra variant data */ -}; - -/** - * struct realtek_smi_ops - vtable for the per-SMI-chiptype operations - * @detect: detects the chiptype - */ -struct realtek_smi_ops { - int (*detect)(struct realtek_smi *smi); - int (*reset_chip)(struct realtek_smi *smi); - int (*setup)(struct realtek_smi *smi); - void (*cleanup)(struct realtek_smi *smi); - int (*get_mib_counter)(struct realtek_smi *smi, - int port, - struct rtl8366_mib_counter *mib, - u64 *mibvalue); - int (*get_vlan_mc)(struct realtek_smi *smi, u32 index, - struct rtl8366_vlan_mc *vlanmc); - int (*set_vlan_mc)(struct realtek_smi *smi, u32 index, - const struct rtl8366_vlan_mc *vlanmc); - int (*get_vlan_4k)(struct realtek_smi *smi, u32 vid, - struct rtl8366_vlan_4k *vlan4k); - int (*set_vlan_4k)(struct realtek_smi *smi, - const struct rtl8366_vlan_4k *vlan4k); - int (*get_mc_index)(struct realtek_smi *smi, int port, int *val); - int (*set_mc_index)(struct realtek_smi *smi, int port, int index); - bool (*is_vlan_valid)(struct realtek_smi *smi, unsigned int vlan); - int (*enable_vlan)(struct realtek_smi *smi, bool enable); - int (*enable_vlan4k)(struct realtek_smi *smi, bool enable); - int (*enable_port)(struct realtek_smi *smi, int port, bool enable); - int (*phy_read)(struct realtek_smi *smi, int phy, int regnum); - int (*phy_write)(struct realtek_smi *smi, int phy, int regnum, - u16 val); -}; - -struct realtek_smi_variant { - const struct dsa_switch_ops *ds_ops; - const struct realtek_smi_ops *ops; - unsigned int clk_delay; - u8 cmd_read; - u8 cmd_write; - size_t chip_data_sz; -}; - -/* SMI core calls */ -int realtek_smi_write_reg_noack(struct realtek_smi *smi, u32 addr, - u32 data); -int realtek_smi_setup_mdio(struct realtek_smi *smi); - -/* RTL8366 library helpers */ -int rtl8366_mc_is_used(struct realtek_smi *smi, int mc_index, int *used); -int rtl8366_set_vlan(struct realtek_smi *smi, int vid, u32 member, - u32 untag, u32 fid); -int rtl8366_set_pvid(struct realtek_smi *smi, unsigned int port, - unsigned int vid); -int rtl8366_enable_vlan4k(struct realtek_smi *smi, bool enable); -int rtl8366_enable_vlan(struct realtek_smi *smi, bool enable); -int rtl8366_reset_vlan(struct realtek_smi *smi); -int rtl8366_vlan_add(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan, - struct netlink_ext_ack *extack); -int rtl8366_vlan_del(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan); -void rtl8366_get_strings(struct dsa_switch *ds, int port, u32 stringset, - uint8_t *data); -int rtl8366_get_sset_count(struct dsa_switch *ds, int port, int sset); -void rtl8366_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *= data); - -extern const struct realtek_smi_variant rtl8366rb_variant; -extern const struct realtek_smi_variant rtl8365mb_variant; - -#endif /* _REALTEK_SMI_H */ diff --git a/drivers/net/dsa/realtek/Kconfig b/drivers/net/dsa/realtek/Kcon= fig new file mode 100644 index 000000000000..1c62212fb0ec --- /dev/null +++ b/drivers/net/dsa/realtek/Kconfig @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-only +menuconfig NET_DSA_REALTEK + tristate "Realtek Ethernet switch family support" + depends on NET_DSA + select NET_DSA_TAG_RTL4_A + select NET_DSA_TAG_RTL8_4 + select FIXED_PHY + select IRQ_DOMAIN + select REALTEK_PHY + select REGMAP + help + Select to enable support for Realtek Ethernet switch chips. + +config NET_DSA_REALTEK_SMI + tristate "Realtek SMI connected switch driver" + depends on NET_DSA_REALTEK + default y + help + Select to enable support for registering switches connected + through SMI. diff --git a/drivers/net/dsa/realtek/Makefile b/drivers/net/dsa/realtek/Mak= efile new file mode 100644 index 000000000000..323b921bfce0 --- /dev/null +++ b/drivers/net/dsa/realtek/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_NET_DSA_REALTEK_SMI) +=3D realtek-smi.o +realtek-smi-objs :=3D realtek-smi-core.o rtl8366.o rtl8366rb.o rtl8365mb= .o diff --git a/drivers/net/dsa/realtek/realtek-smi-core.c b/drivers/net/dsa/r= ealtek/realtek-smi-core.c new file mode 100644 index 000000000000..c66ebd0ee217 --- /dev/null +++ b/drivers/net/dsa/realtek/realtek-smi-core.c @@ -0,0 +1,523 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Realtek Simple Management Interface (SMI) driver + * It can be discussed how "simple" this interface is. + * + * The SMI protocol piggy-backs the MDIO MDC and MDIO signals levels + * but the protocol is not MDIO at all. Instead it is a Realtek + * pecularity that need to bit-bang the lines in a special way to + * communicate with the switch. + * + * ASICs we intend to support with this driver: + * + * RTL8366 - The original version, apparently + * RTL8369 - Similar enough to have the same datsheet as RTL8366 + * RTL8366RB - Probably reads out "RTL8366 revision B", has a quite + * different register layout from the other two + * RTL8366S - Is this "RTL8366 super"? + * RTL8367 - Has an OpenWRT driver as well + * RTL8368S - Seems to be an alternative name for RTL8366RB + * RTL8370 - Also uses SMI + * + * Copyright (C) 2017 Linus Walleij + * Copyright (C) 2010 Antti Sepp=C3=A4l=C3=A4 + * Copyright (C) 2010 Roman Yeryomin + * Copyright (C) 2011 Colin Leitner + * Copyright (C) 2009-2010 Gabor Juhos + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "realtek-smi-core.h" + +#define REALTEK_SMI_ACK_RETRY_COUNT 5 +#define REALTEK_SMI_HW_STOP_DELAY 25 /* msecs */ +#define REALTEK_SMI_HW_START_DELAY 100 /* msecs */ + +static inline void realtek_smi_clk_delay(struct realtek_smi *smi) +{ + ndelay(smi->clk_delay); +} + +static void realtek_smi_start(struct realtek_smi *smi) +{ + /* Set GPIO pins to output mode, with initial state: + * SCK =3D 0, SDA =3D 1 + */ + gpiod_direction_output(smi->mdc, 0); + gpiod_direction_output(smi->mdio, 1); + realtek_smi_clk_delay(smi); + + /* CLK 1: 0 -> 1, 1 -> 0 */ + gpiod_set_value(smi->mdc, 1); + realtek_smi_clk_delay(smi); + gpiod_set_value(smi->mdc, 0); + realtek_smi_clk_delay(smi); + + /* CLK 2: */ + gpiod_set_value(smi->mdc, 1); + realtek_smi_clk_delay(smi); + gpiod_set_value(smi->mdio, 0); + realtek_smi_clk_delay(smi); + gpiod_set_value(smi->mdc, 0); + realtek_smi_clk_delay(smi); + gpiod_set_value(smi->mdio, 1); +} + +static void realtek_smi_stop(struct realtek_smi *smi) +{ + realtek_smi_clk_delay(smi); + gpiod_set_value(smi->mdio, 0); + gpiod_set_value(smi->mdc, 1); + realtek_smi_clk_delay(smi); + gpiod_set_value(smi->mdio, 1); + realtek_smi_clk_delay(smi); + gpiod_set_value(smi->mdc, 1); + realtek_smi_clk_delay(smi); + gpiod_set_value(smi->mdc, 0); + realtek_smi_clk_delay(smi); + gpiod_set_value(smi->mdc, 1); + + /* Add a click */ + realtek_smi_clk_delay(smi); + gpiod_set_value(smi->mdc, 0); + realtek_smi_clk_delay(smi); + gpiod_set_value(smi->mdc, 1); + + /* Set GPIO pins to input mode */ + gpiod_direction_input(smi->mdio); + gpiod_direction_input(smi->mdc); +} + +static void realtek_smi_write_bits(struct realtek_smi *smi, u32 data, u32 = len) +{ + for (; len > 0; len--) { + realtek_smi_clk_delay(smi); + + /* Prepare data */ + gpiod_set_value(smi->mdio, !!(data & (1 << (len - 1)))); + realtek_smi_clk_delay(smi); + + /* Clocking */ + gpiod_set_value(smi->mdc, 1); + realtek_smi_clk_delay(smi); + gpiod_set_value(smi->mdc, 0); + } +} + +static void realtek_smi_read_bits(struct realtek_smi *smi, u32 len, u32 *d= ata) +{ + gpiod_direction_input(smi->mdio); + + for (*data =3D 0; len > 0; len--) { + u32 u; + + realtek_smi_clk_delay(smi); + + /* Clocking */ + gpiod_set_value(smi->mdc, 1); + realtek_smi_clk_delay(smi); + u =3D !!gpiod_get_value(smi->mdio); + gpiod_set_value(smi->mdc, 0); + + *data |=3D (u << (len - 1)); + } + + gpiod_direction_output(smi->mdio, 0); +} + +static int realtek_smi_wait_for_ack(struct realtek_smi *smi) +{ + int retry_cnt; + + retry_cnt =3D 0; + do { + u32 ack; + + realtek_smi_read_bits(smi, 1, &ack); + if (ack =3D=3D 0) + break; + + if (++retry_cnt > REALTEK_SMI_ACK_RETRY_COUNT) { + dev_err(smi->dev, "ACK timeout\n"); + return -ETIMEDOUT; + } + } while (1); + + return 0; +} + +static int realtek_smi_write_byte(struct realtek_smi *smi, u8 data) +{ + realtek_smi_write_bits(smi, data, 8); + return realtek_smi_wait_for_ack(smi); +} + +static int realtek_smi_write_byte_noack(struct realtek_smi *smi, u8 data) +{ + realtek_smi_write_bits(smi, data, 8); + return 0; +} + +static int realtek_smi_read_byte0(struct realtek_smi *smi, u8 *data) +{ + u32 t; + + /* Read data */ + realtek_smi_read_bits(smi, 8, &t); + *data =3D (t & 0xff); + + /* Send an ACK */ + realtek_smi_write_bits(smi, 0x00, 1); + + return 0; +} + +static int realtek_smi_read_byte1(struct realtek_smi *smi, u8 *data) +{ + u32 t; + + /* Read data */ + realtek_smi_read_bits(smi, 8, &t); + *data =3D (t & 0xff); + + /* Send an ACK */ + realtek_smi_write_bits(smi, 0x01, 1); + + return 0; +} + +static int realtek_smi_read_reg(struct realtek_smi *smi, u32 addr, u32 *da= ta) +{ + unsigned long flags; + u8 lo =3D 0; + u8 hi =3D 0; + int ret; + + spin_lock_irqsave(&smi->lock, flags); + + realtek_smi_start(smi); + + /* Send READ command */ + ret =3D realtek_smi_write_byte(smi, smi->cmd_read); + if (ret) + goto out; + + /* Set ADDR[7:0] */ + ret =3D realtek_smi_write_byte(smi, addr & 0xff); + if (ret) + goto out; + + /* Set ADDR[15:8] */ + ret =3D realtek_smi_write_byte(smi, addr >> 8); + if (ret) + goto out; + + /* Read DATA[7:0] */ + realtek_smi_read_byte0(smi, &lo); + /* Read DATA[15:8] */ + realtek_smi_read_byte1(smi, &hi); + + *data =3D ((u32)lo) | (((u32)hi) << 8); + + ret =3D 0; + + out: + realtek_smi_stop(smi); + spin_unlock_irqrestore(&smi->lock, flags); + + return ret; +} + +static int realtek_smi_write_reg(struct realtek_smi *smi, + u32 addr, u32 data, bool ack) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&smi->lock, flags); + + realtek_smi_start(smi); + + /* Send WRITE command */ + ret =3D realtek_smi_write_byte(smi, smi->cmd_write); + if (ret) + goto out; + + /* Set ADDR[7:0] */ + ret =3D realtek_smi_write_byte(smi, addr & 0xff); + if (ret) + goto out; + + /* Set ADDR[15:8] */ + ret =3D realtek_smi_write_byte(smi, addr >> 8); + if (ret) + goto out; + + /* Write DATA[7:0] */ + ret =3D realtek_smi_write_byte(smi, data & 0xff); + if (ret) + goto out; + + /* Write DATA[15:8] */ + if (ack) + ret =3D realtek_smi_write_byte(smi, data >> 8); + else + ret =3D realtek_smi_write_byte_noack(smi, data >> 8); + if (ret) + goto out; + + ret =3D 0; + + out: + realtek_smi_stop(smi); + spin_unlock_irqrestore(&smi->lock, flags); + + return ret; +} + +/* There is one single case when we need to use this accessor and that + * is when issueing soft reset. Since the device reset as soon as we write + * that bit, no ACK will come back for natural reasons. + */ +int realtek_smi_write_reg_noack(struct realtek_smi *smi, u32 addr, + u32 data) +{ + return realtek_smi_write_reg(smi, addr, data, false); +} +EXPORT_SYMBOL_GPL(realtek_smi_write_reg_noack); + +/* Regmap accessors */ + +static int realtek_smi_write(void *ctx, u32 reg, u32 val) +{ + struct realtek_smi *smi =3D ctx; + + return realtek_smi_write_reg(smi, reg, val, true); +} + +static int realtek_smi_read(void *ctx, u32 reg, u32 *val) +{ + struct realtek_smi *smi =3D ctx; + + return realtek_smi_read_reg(smi, reg, val); +} + +static const struct regmap_config realtek_smi_mdio_regmap_config =3D { + .reg_bits =3D 10, /* A4..A0 R4..R0 */ + .val_bits =3D 16, + .reg_stride =3D 1, + /* PHY regs are at 0x8000 */ + .max_register =3D 0xffff, + .reg_format_endian =3D REGMAP_ENDIAN_BIG, + .reg_read =3D realtek_smi_read, + .reg_write =3D realtek_smi_write, + .cache_type =3D REGCACHE_NONE, +}; + +static int realtek_smi_mdio_read(struct mii_bus *bus, int addr, int regnum) +{ + struct realtek_smi *smi =3D bus->priv; + + return smi->ops->phy_read(smi, addr, regnum); +} + +static int realtek_smi_mdio_write(struct mii_bus *bus, int addr, int regnu= m, + u16 val) +{ + struct realtek_smi *smi =3D bus->priv; + + return smi->ops->phy_write(smi, addr, regnum, val); +} + +int realtek_smi_setup_mdio(struct realtek_smi *smi) +{ + struct device_node *mdio_np; + int ret; + + mdio_np =3D of_get_compatible_child(smi->dev->of_node, "realtek,smi-mdio"= ); + if (!mdio_np) { + dev_err(smi->dev, "no MDIO bus node\n"); + return -ENODEV; + } + + smi->slave_mii_bus =3D devm_mdiobus_alloc(smi->dev); + if (!smi->slave_mii_bus) { + ret =3D -ENOMEM; + goto err_put_node; + } + smi->slave_mii_bus->priv =3D smi; + smi->slave_mii_bus->name =3D "SMI slave MII"; + smi->slave_mii_bus->read =3D realtek_smi_mdio_read; + smi->slave_mii_bus->write =3D realtek_smi_mdio_write; + snprintf(smi->slave_mii_bus->id, MII_BUS_ID_SIZE, "SMI-%d", + smi->ds->index); + smi->slave_mii_bus->dev.of_node =3D mdio_np; + smi->slave_mii_bus->parent =3D smi->dev; + smi->ds->slave_mii_bus =3D smi->slave_mii_bus; + + ret =3D devm_of_mdiobus_register(smi->dev, smi->slave_mii_bus, mdio_np); + if (ret) { + dev_err(smi->dev, "unable to register MDIO bus %s\n", + smi->slave_mii_bus->id); + goto err_put_node; + } + + return 0; + +err_put_node: + of_node_put(mdio_np); + + return ret; +} + +static int realtek_smi_probe(struct platform_device *pdev) +{ + const struct realtek_smi_variant *var; + struct device *dev =3D &pdev->dev; + struct realtek_smi *smi; + struct device_node *np; + int ret; + + var =3D of_device_get_match_data(dev); + np =3D dev->of_node; + + smi =3D devm_kzalloc(dev, sizeof(*smi) + var->chip_data_sz, GFP_KERNEL); + if (!smi) + return -ENOMEM; + smi->chip_data =3D (void *)smi + sizeof(*smi); + smi->map =3D devm_regmap_init(dev, NULL, smi, + &realtek_smi_mdio_regmap_config); + if (IS_ERR(smi->map)) { + ret =3D PTR_ERR(smi->map); + dev_err(dev, "regmap init failed: %d\n", ret); + return ret; + } + + /* Link forward and backward */ + smi->dev =3D dev; + smi->clk_delay =3D var->clk_delay; + smi->cmd_read =3D var->cmd_read; + smi->cmd_write =3D var->cmd_write; + smi->ops =3D var->ops; + + dev_set_drvdata(dev, smi); + spin_lock_init(&smi->lock); + + /* TODO: if power is software controlled, set up any regulators here */ + + /* Assert then deassert RESET */ + smi->reset =3D devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(smi->reset)) { + dev_err(dev, "failed to get RESET GPIO\n"); + return PTR_ERR(smi->reset); + } + msleep(REALTEK_SMI_HW_STOP_DELAY); + gpiod_set_value(smi->reset, 0); + msleep(REALTEK_SMI_HW_START_DELAY); + dev_info(dev, "deasserted RESET\n"); + + /* Fetch MDIO pins */ + smi->mdc =3D devm_gpiod_get_optional(dev, "mdc", GPIOD_OUT_LOW); + if (IS_ERR(smi->mdc)) + return PTR_ERR(smi->mdc); + smi->mdio =3D devm_gpiod_get_optional(dev, "mdio", GPIOD_OUT_LOW); + if (IS_ERR(smi->mdio)) + return PTR_ERR(smi->mdio); + + smi->leds_disabled =3D of_property_read_bool(np, "realtek,disable-leds"); + + ret =3D smi->ops->detect(smi); + if (ret) { + dev_err(dev, "unable to detect switch\n"); + return ret; + } + + smi->ds =3D devm_kzalloc(dev, sizeof(*smi->ds), GFP_KERNEL); + if (!smi->ds) + return -ENOMEM; + + smi->ds->dev =3D dev; + smi->ds->num_ports =3D smi->num_ports; + smi->ds->priv =3D smi; + + smi->ds->ops =3D var->ds_ops; + ret =3D dsa_register_switch(smi->ds); + if (ret) { + dev_err(dev, "unable to register switch ret =3D %d\n", ret); + return ret; + } + return 0; +} + +static int realtek_smi_remove(struct platform_device *pdev) +{ + struct realtek_smi *smi =3D platform_get_drvdata(pdev); + + if (!smi) + return 0; + + dsa_unregister_switch(smi->ds); + if (smi->slave_mii_bus) + of_node_put(smi->slave_mii_bus->dev.of_node); + gpiod_set_value(smi->reset, 1); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static void realtek_smi_shutdown(struct platform_device *pdev) +{ + struct realtek_smi *smi =3D platform_get_drvdata(pdev); + + if (!smi) + return; + + dsa_switch_shutdown(smi->ds); + + platform_set_drvdata(pdev, NULL); +} + +static const struct of_device_id realtek_smi_of_match[] =3D { + { + .compatible =3D "realtek,rtl8366rb", + .data =3D &rtl8366rb_variant, + }, + { + /* FIXME: add support for RTL8366S and more */ + .compatible =3D "realtek,rtl8366s", + .data =3D NULL, + }, + { + .compatible =3D "realtek,rtl8365mb", + .data =3D &rtl8365mb_variant, + }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, realtek_smi_of_match); + +static struct platform_driver realtek_smi_driver =3D { + .driver =3D { + .name =3D "realtek-smi", + .of_match_table =3D of_match_ptr(realtek_smi_of_match), + }, + .probe =3D realtek_smi_probe, + .remove =3D realtek_smi_remove, + .shutdown =3D realtek_smi_shutdown, +}; +module_platform_driver(realtek_smi_driver); + +MODULE_LICENSE("GPL"); diff --git a/drivers/net/dsa/realtek/realtek-smi-core.h b/drivers/net/dsa/r= ealtek/realtek-smi-core.h new file mode 100644 index 000000000000..faed387d8db3 --- /dev/null +++ b/drivers/net/dsa/realtek/realtek-smi-core.h @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Realtek SMI interface driver defines + * + * Copyright (C) 2017 Linus Walleij + * Copyright (C) 2009-2010 Gabor Juhos + */ + +#ifndef _REALTEK_SMI_H +#define _REALTEK_SMI_H + +#include +#include +#include +#include + +struct realtek_smi_ops; +struct dentry; +struct inode; +struct file; + +struct rtl8366_mib_counter { + unsigned int base; + unsigned int offset; + unsigned int length; + const char *name; +}; + +/* + * struct rtl8366_vlan_mc - Virtual LAN member configuration + */ +struct rtl8366_vlan_mc { + u16 vid; + u16 untag; + u16 member; + u8 fid; + u8 priority; +}; + +struct rtl8366_vlan_4k { + u16 vid; + u16 untag; + u16 member; + u8 fid; +}; + +struct realtek_smi { + struct device *dev; + struct gpio_desc *reset; + struct gpio_desc *mdc; + struct gpio_desc *mdio; + struct regmap *map; + struct mii_bus *slave_mii_bus; + + unsigned int clk_delay; + u8 cmd_read; + u8 cmd_write; + spinlock_t lock; /* Locks around command writes */ + struct dsa_switch *ds; + struct irq_domain *irqdomain; + bool leds_disabled; + + unsigned int cpu_port; + unsigned int num_ports; + unsigned int num_vlan_mc; + unsigned int num_mib_counters; + struct rtl8366_mib_counter *mib_counters; + + const struct realtek_smi_ops *ops; + + int vlan_enabled; + int vlan4k_enabled; + + char buf[4096]; + void *chip_data; /* Per-chip extra variant data */ +}; + +/* + * struct realtek_smi_ops - vtable for the per-SMI-chiptype operations + * @detect: detects the chiptype + */ +struct realtek_smi_ops { + int (*detect)(struct realtek_smi *smi); + int (*reset_chip)(struct realtek_smi *smi); + int (*setup)(struct realtek_smi *smi); + void (*cleanup)(struct realtek_smi *smi); + int (*get_mib_counter)(struct realtek_smi *smi, + int port, + struct rtl8366_mib_counter *mib, + u64 *mibvalue); + int (*get_vlan_mc)(struct realtek_smi *smi, u32 index, + struct rtl8366_vlan_mc *vlanmc); + int (*set_vlan_mc)(struct realtek_smi *smi, u32 index, + const struct rtl8366_vlan_mc *vlanmc); + int (*get_vlan_4k)(struct realtek_smi *smi, u32 vid, + struct rtl8366_vlan_4k *vlan4k); + int (*set_vlan_4k)(struct realtek_smi *smi, + const struct rtl8366_vlan_4k *vlan4k); + int (*get_mc_index)(struct realtek_smi *smi, int port, int *val); + int (*set_mc_index)(struct realtek_smi *smi, int port, int index); + bool (*is_vlan_valid)(struct realtek_smi *smi, unsigned int vlan); + int (*enable_vlan)(struct realtek_smi *smi, bool enable); + int (*enable_vlan4k)(struct realtek_smi *smi, bool enable); + int (*enable_port)(struct realtek_smi *smi, int port, bool enable); + int (*phy_read)(struct realtek_smi *smi, int phy, int regnum); + int (*phy_write)(struct realtek_smi *smi, int phy, int regnum, + u16 val); +}; + +struct realtek_smi_variant { + const struct dsa_switch_ops *ds_ops; + const struct realtek_smi_ops *ops; + unsigned int clk_delay; + u8 cmd_read; + u8 cmd_write; + size_t chip_data_sz; +}; + +/* SMI core calls */ +int realtek_smi_write_reg_noack(struct realtek_smi *smi, u32 addr, + u32 data); +int realtek_smi_setup_mdio(struct realtek_smi *smi); + +/* RTL8366 library helpers */ +int rtl8366_mc_is_used(struct realtek_smi *smi, int mc_index, int *used); +int rtl8366_set_vlan(struct realtek_smi *smi, int vid, u32 member, + u32 untag, u32 fid); +int rtl8366_set_pvid(struct realtek_smi *smi, unsigned int port, + unsigned int vid); +int rtl8366_enable_vlan4k(struct realtek_smi *smi, bool enable); +int rtl8366_enable_vlan(struct realtek_smi *smi, bool enable); +int rtl8366_reset_vlan(struct realtek_smi *smi); +int rtl8366_vlan_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan, + struct netlink_ext_ack *extack); +int rtl8366_vlan_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan); +void rtl8366_get_strings(struct dsa_switch *ds, int port, u32 stringset, + uint8_t *data); +int rtl8366_get_sset_count(struct dsa_switch *ds, int port, int sset); +void rtl8366_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *= data); + +extern const struct realtek_smi_variant rtl8366rb_variant; +extern const struct realtek_smi_variant rtl8365mb_variant; + +#endif /* _REALTEK_SMI_H */ diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/= rtl8365mb.c new file mode 100644 index 000000000000..48c0e3e46600 --- /dev/null +++ b/drivers/net/dsa/realtek/rtl8365mb.c @@ -0,0 +1,1986 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Realtek SMI subdriver for the Realtek RTL8365MB-VC ethernet switch. + * + * Copyright (C) 2021 Alvin =C5=A0ipraga + * Copyright (C) 2021 Michael Rasmussen + * + * The RTL8365MB-VC is a 4+1 port 10/100/1000M switch controller. It inclu= des 4 + * integrated PHYs for the user facing ports, and an extension interface w= hich + * can be connected to the CPU - or another PHY - via either MII, RMII, or + * RGMII. The switch is configured via the Realtek Simple Management Inter= face + * (SMI), which uses the MDIO/MDC lines. + * + * Below is a simplified block diagram of the chip and its relevant interf= aces. + * + * .-----------------------------------. + * | | + * UTP <---------------> Giga PHY <-> PCS <-> P0 GMAC | + * UTP <---------------> Giga PHY <-> PCS <-> P1 GMAC | + * UTP <---------------> Giga PHY <-> PCS <-> P2 GMAC | + * UTP <---------------> Giga PHY <-> PCS <-> P3 GMAC | + * | | + * CPU/PHY <-MII/RMII/RGMII---> Extension <---> Extension | + * | interface 1 GMAC 1 | + * | | + * SMI driver/ <-MDC/SCL---> Management ~~~~~~~~~~~~~~ | + * EEPROM <-MDIO/SDA--> interface ~REALTEK ~~~~~ | + * | ~RTL8365MB ~~~ | + * | ~GXXXC TAIWAN~ | + * GPIO <--------------> Reset ~~~~~~~~~~~~~~ | + * | | + * Interrupt <----------> Link UP/DOWN events | + * controller | | + * '-----------------------------------' + * + * The driver uses DSA to integrate the 4 user and 1 extension ports into = the + * kernel. Netdevices are created for the user ports, as are PHY devices f= or + * their integrated PHYs. The device tree firmware should also specify the= link + * partner of the extension port - either via a fixed-link or other phy-ha= ndle. + * See the device tree bindings for more detailed information. Note that t= he + * driver has only been tested with a fixed-link, but in principle it shou= ld not + * matter. + * + * NOTE: Currently, only the RGMII interface is implemented in this driver. + * + * The interrupt line is asserted on link UP/DOWN events. The driver creat= es a + * custom irqchip to handle this interrupt and demultiplex the events by r= eading + * the status registers via SMI. Interrupts are then propagated to the rel= evant + * PHY device. + * + * The EEPROM contains initial register values which the chip will read ov= er I2C + * upon hardware reset. It is also possible to omit the EEPROM. In both ca= ses, + * the driver will manually reprogram some registers using jam tables to r= each + * an initial state defined by the vendor driver. + * + * This Linux driver is written based on an OS-agnostic vendor driver from + * Realtek. The reference GPL-licensed sources can be found in the OpenWrt + * source tree under the name rtl8367c. The vendor driver claims to suppor= t a + * number of similar switch controllers from Realtek, but the only hardwar= e we + * have is the RTL8365MB-VC. Moreover, there does not seem to be any chip = under + * the name RTL8367C. Although one wishes that the 'C' stood for some kind= of + * common hardware revision, there exist examples of chips with the suffix= -VC + * which are explicitly not supported by the rtl8367c driver and which ins= tead + * require the rtl8367d vendor driver. With all this uncertainty, the driv= er has + * been modestly named rtl8365mb. Future implementors may wish to rename t= hings + * accordingly. + * + * In the same family of chips, some carry up to 8 user ports and up to 2 + * extension ports. Where possible this driver tries to make things generi= c, but + * more work must be done to support these configurations. According to + * documentation from Realtek, the family should include the following chi= ps: + * + * - RTL8363NB + * - RTL8363NB-VB + * - RTL8363SC + * - RTL8363SC-VB + * - RTL8364NB + * - RTL8364NB-VB + * - RTL8365MB-VC + * - RTL8366SC + * - RTL8367RB-VB + * - RTL8367SB + * - RTL8367S + * - RTL8370MB + * - RTL8310SR + * + * Some of the register logic for these additional chips has been skipped = over + * while implementing this driver. It is therefore not possible to assume = that + * things will work out-of-the-box for other chips, and a careful review o= f the + * vendor driver may be needed to expand support. The RTL8365MB-VC seems t= o be + * one of the simpler chips. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "realtek-smi-core.h" + +/* Chip-specific data and limits */ +#define RTL8365MB_CHIP_ID_8365MB_VC 0x6367 +#define RTL8365MB_CPU_PORT_NUM_8365MB_VC 6 +#define RTL8365MB_LEARN_LIMIT_MAX_8365MB_VC 2112 + +/* Family-specific data and limits */ +#define RTL8365MB_PHYADDRMAX 7 +#define RTL8365MB_NUM_PHYREGS 32 +#define RTL8365MB_PHYREGMAX (RTL8365MB_NUM_PHYREGS - 1) +#define RTL8365MB_MAX_NUM_PORTS (RTL8365MB_CPU_PORT_NUM_8365MB_VC + 1) + +/* Chip identification registers */ +#define RTL8365MB_CHIP_ID_REG 0x1300 + +#define RTL8365MB_CHIP_VER_REG 0x1301 + +#define RTL8365MB_MAGIC_REG 0x13C2 +#define RTL8365MB_MAGIC_VALUE 0x0249 + +/* Chip reset register */ +#define RTL8365MB_CHIP_RESET_REG 0x1322 +#define RTL8365MB_CHIP_RESET_SW_MASK 0x0002 +#define RTL8365MB_CHIP_RESET_HW_MASK 0x0001 + +/* Interrupt polarity register */ +#define RTL8365MB_INTR_POLARITY_REG 0x1100 +#define RTL8365MB_INTR_POLARITY_MASK 0x0001 +#define RTL8365MB_INTR_POLARITY_HIGH 0 +#define RTL8365MB_INTR_POLARITY_LOW 1 + +/* Interrupt control/status register - enable/check specific interrupt typ= es */ +#define RTL8365MB_INTR_CTRL_REG 0x1101 +#define RTL8365MB_INTR_STATUS_REG 0x1102 +#define RTL8365MB_INTR_SLIENT_START_2_MASK 0x1000 +#define RTL8365MB_INTR_SLIENT_START_MASK 0x0800 +#define RTL8365MB_INTR_ACL_ACTION_MASK 0x0200 +#define RTL8365MB_INTR_CABLE_DIAG_FIN_MASK 0x0100 +#define RTL8365MB_INTR_INTERRUPT_8051_MASK 0x0080 +#define RTL8365MB_INTR_LOOP_DETECTION_MASK 0x0040 +#define RTL8365MB_INTR_GREEN_TIMER_MASK 0x0020 +#define RTL8365MB_INTR_SPECIAL_CONGEST_MASK 0x0010 +#define RTL8365MB_INTR_SPEED_CHANGE_MASK 0x0008 +#define RTL8365MB_INTR_LEARN_OVER_MASK 0x0004 +#define RTL8365MB_INTR_METER_EXCEEDED_MASK 0x0002 +#define RTL8365MB_INTR_LINK_CHANGE_MASK 0x0001 +#define RTL8365MB_INTR_ALL_MASK \ + (RTL8365MB_INTR_SLIENT_START_2_MASK | \ + RTL8365MB_INTR_SLIENT_START_MASK | \ + RTL8365MB_INTR_ACL_ACTION_MASK | \ + RTL8365MB_INTR_CABLE_DIAG_FIN_MASK | \ + RTL8365MB_INTR_INTERRUPT_8051_MASK | \ + RTL8365MB_INTR_LOOP_DETECTION_MASK | \ + RTL8365MB_INTR_GREEN_TIMER_MASK | \ + RTL8365MB_INTR_SPECIAL_CONGEST_MASK | \ + RTL8365MB_INTR_SPEED_CHANGE_MASK | \ + RTL8365MB_INTR_LEARN_OVER_MASK | \ + RTL8365MB_INTR_METER_EXCEEDED_MASK | \ + RTL8365MB_INTR_LINK_CHANGE_MASK) + +/* Per-port interrupt type status registers */ +#define RTL8365MB_PORT_LINKDOWN_IND_REG 0x1106 +#define RTL8365MB_PORT_LINKDOWN_IND_MASK 0x07FF + +#define RTL8365MB_PORT_LINKUP_IND_REG 0x1107 +#define RTL8365MB_PORT_LINKUP_IND_MASK 0x07FF + +/* PHY indirect access registers */ +#define RTL8365MB_INDIRECT_ACCESS_CTRL_REG 0x1F00 +#define RTL8365MB_INDIRECT_ACCESS_CTRL_RW_MASK 0x0002 +#define RTL8365MB_INDIRECT_ACCESS_CTRL_RW_READ 0 +#define RTL8365MB_INDIRECT_ACCESS_CTRL_RW_WRITE 1 +#define RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_MASK 0x0001 +#define RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_VALUE 1 +#define RTL8365MB_INDIRECT_ACCESS_STATUS_REG 0x1F01 +#define RTL8365MB_INDIRECT_ACCESS_ADDRESS_REG 0x1F02 +#define RTL8365MB_INDIRECT_ACCESS_ADDRESS_OCPADR_5_1_MASK GENMASK(4, 0) +#define RTL8365MB_INDIRECT_ACCESS_ADDRESS_PHYNUM_MASK GENMASK(7, 5) +#define RTL8365MB_INDIRECT_ACCESS_ADDRESS_OCPADR_9_6_MASK GENMASK(11, 8) +#define RTL8365MB_PHY_BASE 0x2000 +#define RTL8365MB_INDIRECT_ACCESS_WRITE_DATA_REG 0x1F03 +#define RTL8365MB_INDIRECT_ACCESS_READ_DATA_REG 0x1F04 + +/* PHY OCP address prefix register */ +#define RTL8365MB_GPHY_OCP_MSB_0_REG 0x1D15 +#define RTL8365MB_GPHY_OCP_MSB_0_CFG_CPU_OCPADR_MASK 0x0FC0 +#define RTL8365MB_PHY_OCP_ADDR_PREFIX_MASK 0xFC00 + +/* The PHY OCP addresses of PHY registers 0~31 start here */ +#define RTL8365MB_PHY_OCP_ADDR_PHYREG_BASE 0xA400 + +/* EXT port interface mode values - used in DIGITAL_INTERFACE_SELECT */ +#define RTL8365MB_EXT_PORT_MODE_DISABLE 0 +#define RTL8365MB_EXT_PORT_MODE_RGMII 1 +#define RTL8365MB_EXT_PORT_MODE_MII_MAC 2 +#define RTL8365MB_EXT_PORT_MODE_MII_PHY 3 +#define RTL8365MB_EXT_PORT_MODE_TMII_MAC 4 +#define RTL8365MB_EXT_PORT_MODE_TMII_PHY 5 +#define RTL8365MB_EXT_PORT_MODE_GMII 6 +#define RTL8365MB_EXT_PORT_MODE_RMII_MAC 7 +#define RTL8365MB_EXT_PORT_MODE_RMII_PHY 8 +#define RTL8365MB_EXT_PORT_MODE_SGMII 9 +#define RTL8365MB_EXT_PORT_MODE_HSGMII 10 +#define RTL8365MB_EXT_PORT_MODE_1000X_100FX 11 +#define RTL8365MB_EXT_PORT_MODE_1000X 12 +#define RTL8365MB_EXT_PORT_MODE_100FX 13 + +/* EXT port interface mode configuration registers 0~1 */ +#define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG0 0x1305 +#define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1 0x13C3 +#define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG(_extport) \ + (RTL8365MB_DIGITAL_INTERFACE_SELECT_REG0 + \ + ((_extport) >> 1) * (0x13C3 - 0x1305)) +#define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(_extport) \ + (0xF << (((_extport) % 2))) +#define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET(_extport) \ + (((_extport) % 2) * 4) + +/* EXT port RGMII TX/RX delay configuration registers 1~2 */ +#define RTL8365MB_EXT_RGMXF_REG1 0x1307 +#define RTL8365MB_EXT_RGMXF_REG2 0x13C5 +#define RTL8365MB_EXT_RGMXF_REG(_extport) \ + (RTL8365MB_EXT_RGMXF_REG1 + \ + (((_extport) >> 1) * (0x13C5 - 0x1307))) +#define RTL8365MB_EXT_RGMXF_RXDELAY_MASK 0x0007 +#define RTL8365MB_EXT_RGMXF_TXDELAY_MASK 0x0008 + +/* External port speed values - used in DIGITAL_INTERFACE_FORCE */ +#define RTL8365MB_PORT_SPEED_10M 0 +#define RTL8365MB_PORT_SPEED_100M 1 +#define RTL8365MB_PORT_SPEED_1000M 2 + +/* EXT port force configuration registers 0~2 */ +#define RTL8365MB_DIGITAL_INTERFACE_FORCE_REG0 0x1310 +#define RTL8365MB_DIGITAL_INTERFACE_FORCE_REG1 0x1311 +#define RTL8365MB_DIGITAL_INTERFACE_FORCE_REG2 0x13C4 +#define RTL8365MB_DIGITAL_INTERFACE_FORCE_REG(_extport) \ + (RTL8365MB_DIGITAL_INTERFACE_FORCE_REG0 + \ + ((_extport) & 0x1) + \ + ((((_extport) >> 1) & 0x1) * (0x13C4 - 0x1310))) +#define RTL8365MB_DIGITAL_INTERFACE_FORCE_EN_MASK 0x1000 +#define RTL8365MB_DIGITAL_INTERFACE_FORCE_NWAY_MASK 0x0080 +#define RTL8365MB_DIGITAL_INTERFACE_FORCE_TXPAUSE_MASK 0x0040 +#define RTL8365MB_DIGITAL_INTERFACE_FORCE_RXPAUSE_MASK 0x0020 +#define RTL8365MB_DIGITAL_INTERFACE_FORCE_LINK_MASK 0x0010 +#define RTL8365MB_DIGITAL_INTERFACE_FORCE_DUPLEX_MASK 0x0004 +#define RTL8365MB_DIGITAL_INTERFACE_FORCE_SPEED_MASK 0x0003 + +/* CPU port mask register - controls which ports are treated as CPU ports = */ +#define RTL8365MB_CPU_PORT_MASK_REG 0x1219 +#define RTL8365MB_CPU_PORT_MASK_MASK 0x07FF + +/* CPU control register */ +#define RTL8365MB_CPU_CTRL_REG 0x121A +#define RTL8365MB_CPU_CTRL_TRAP_PORT_EXT_MASK 0x0400 +#define RTL8365MB_CPU_CTRL_TAG_FORMAT_MASK 0x0200 +#define RTL8365MB_CPU_CTRL_RXBYTECOUNT_MASK 0x0080 +#define RTL8365MB_CPU_CTRL_TAG_POSITION_MASK 0x0040 +#define RTL8365MB_CPU_CTRL_TRAP_PORT_MASK 0x0038 +#define RTL8365MB_CPU_CTRL_INSERTMODE_MASK 0x0006 +#define RTL8365MB_CPU_CTRL_EN_MASK 0x0001 + +/* Maximum packet length register */ +#define RTL8365MB_CFG0_MAX_LEN_REG 0x088C +#define RTL8365MB_CFG0_MAX_LEN_MASK 0x3FFF + +/* Port learning limit registers */ +#define RTL8365MB_LUT_PORT_LEARN_LIMIT_BASE 0x0A20 +#define RTL8365MB_LUT_PORT_LEARN_LIMIT_REG(_physport) \ + (RTL8365MB_LUT_PORT_LEARN_LIMIT_BASE + (_physport)) + +/* Port isolation (forwarding mask) registers */ +#define RTL8365MB_PORT_ISOLATION_REG_BASE 0x08A2 +#define RTL8365MB_PORT_ISOLATION_REG(_physport) \ + (RTL8365MB_PORT_ISOLATION_REG_BASE + (_physport)) +#define RTL8365MB_PORT_ISOLATION_MASK 0x07FF + +/* MSTP port state registers - indexed by tree instancrSTI (tree ine */ +#define RTL8365MB_MSTI_CTRL_BASE 0x0A00 +#define RTL8365MB_MSTI_CTRL_REG(_msti, _physport) \ + (RTL8365MB_MSTI_CTRL_BASE + ((_msti) << 1) + ((_physport) >> 3)) +#define RTL8365MB_MSTI_CTRL_PORT_STATE_OFFSET(_physport) ((_physport) <<= 1) +#define RTL8365MB_MSTI_CTRL_PORT_STATE_MASK(_physport) \ + (0x3 << RTL8365MB_MSTI_CTRL_PORT_STATE_OFFSET((_physport))) + +/* MIB counter value registers */ +#define RTL8365MB_MIB_COUNTER_BASE 0x1000 +#define RTL8365MB_MIB_COUNTER_REG(_x) (RTL8365MB_MIB_COUNTER_BASE + (_x)) + +/* MIB counter address register */ +#define RTL8365MB_MIB_ADDRESS_REG 0x1004 +#define RTL8365MB_MIB_ADDRESS_PORT_OFFSET 0x007C +#define RTL8365MB_MIB_ADDRESS(_p, _x) \ + (((RTL8365MB_MIB_ADDRESS_PORT_OFFSET) * (_p) + (_x)) >> 2) + +#define RTL8365MB_MIB_CTRL0_REG 0x1005 +#define RTL8365MB_MIB_CTRL0_RESET_MASK 0x0002 +#define RTL8365MB_MIB_CTRL0_BUSY_MASK 0x0001 + +/* The DSA callback .get_stats64 runs in atomic context, so we are not all= owed + * to block. On the other hand, accessing MIB counters absolutely requires= us to + * block. The solution is thus to schedule work which polls the MIB counte= rs + * asynchronously and updates some private data, which the callback can th= en + * fetch atomically. Three seconds should be a good enough polling interva= l. + */ +#define RTL8365MB_STATS_INTERVAL_JIFFIES (3 * HZ) + +enum rtl8365mb_mib_counter_index { + RTL8365MB_MIB_ifInOctets, + RTL8365MB_MIB_dot3StatsFCSErrors, + RTL8365MB_MIB_dot3StatsSymbolErrors, + RTL8365MB_MIB_dot3InPauseFrames, + RTL8365MB_MIB_dot3ControlInUnknownOpcodes, + RTL8365MB_MIB_etherStatsFragments, + RTL8365MB_MIB_etherStatsJabbers, + RTL8365MB_MIB_ifInUcastPkts, + RTL8365MB_MIB_etherStatsDropEvents, + RTL8365MB_MIB_ifInMulticastPkts, + RTL8365MB_MIB_ifInBroadcastPkts, + RTL8365MB_MIB_inMldChecksumError, + RTL8365MB_MIB_inIgmpChecksumError, + RTL8365MB_MIB_inMldSpecificQuery, + RTL8365MB_MIB_inMldGeneralQuery, + RTL8365MB_MIB_inIgmpSpecificQuery, + RTL8365MB_MIB_inIgmpGeneralQuery, + RTL8365MB_MIB_inMldLeaves, + RTL8365MB_MIB_inIgmpLeaves, + RTL8365MB_MIB_etherStatsOctets, + RTL8365MB_MIB_etherStatsUnderSizePkts, + RTL8365MB_MIB_etherOversizeStats, + RTL8365MB_MIB_etherStatsPkts64Octets, + RTL8365MB_MIB_etherStatsPkts65to127Octets, + RTL8365MB_MIB_etherStatsPkts128to255Octets, + RTL8365MB_MIB_etherStatsPkts256to511Octets, + RTL8365MB_MIB_etherStatsPkts512to1023Octets, + RTL8365MB_MIB_etherStatsPkts1024to1518Octets, + RTL8365MB_MIB_ifOutOctets, + RTL8365MB_MIB_dot3StatsSingleCollisionFrames, + RTL8365MB_MIB_dot3StatsMultipleCollisionFrames, + RTL8365MB_MIB_dot3StatsDeferredTransmissions, + RTL8365MB_MIB_dot3StatsLateCollisions, + RTL8365MB_MIB_etherStatsCollisions, + RTL8365MB_MIB_dot3StatsExcessiveCollisions, + RTL8365MB_MIB_dot3OutPauseFrames, + RTL8365MB_MIB_ifOutDiscards, + RTL8365MB_MIB_dot1dTpPortInDiscards, + RTL8365MB_MIB_ifOutUcastPkts, + RTL8365MB_MIB_ifOutMulticastPkts, + RTL8365MB_MIB_ifOutBroadcastPkts, + RTL8365MB_MIB_outOampduPkts, + RTL8365MB_MIB_inOampduPkts, + RTL8365MB_MIB_inIgmpJoinsSuccess, + RTL8365MB_MIB_inIgmpJoinsFail, + RTL8365MB_MIB_inMldJoinsSuccess, + RTL8365MB_MIB_inMldJoinsFail, + RTL8365MB_MIB_inReportSuppressionDrop, + RTL8365MB_MIB_inLeaveSuppressionDrop, + RTL8365MB_MIB_outIgmpReports, + RTL8365MB_MIB_outIgmpLeaves, + RTL8365MB_MIB_outIgmpGeneralQuery, + RTL8365MB_MIB_outIgmpSpecificQuery, + RTL8365MB_MIB_outMldReports, + RTL8365MB_MIB_outMldLeaves, + RTL8365MB_MIB_outMldGeneralQuery, + RTL8365MB_MIB_outMldSpecificQuery, + RTL8365MB_MIB_inKnownMulticastPkts, + RTL8365MB_MIB_END, +}; + +struct rtl8365mb_mib_counter { + u32 offset; + u32 length; + const char *name; +}; + +#define RTL8365MB_MAKE_MIB_COUNTER(_offset, _length, _name) \ + [RTL8365MB_MIB_ ## _name] =3D { _offset, _length, #_name } + +static struct rtl8365mb_mib_counter rtl8365mb_mib_counters[] =3D { + RTL8365MB_MAKE_MIB_COUNTER(0, 4, ifInOctets), + RTL8365MB_MAKE_MIB_COUNTER(4, 2, dot3StatsFCSErrors), + RTL8365MB_MAKE_MIB_COUNTER(6, 2, dot3StatsSymbolErrors), + RTL8365MB_MAKE_MIB_COUNTER(8, 2, dot3InPauseFrames), + RTL8365MB_MAKE_MIB_COUNTER(10, 2, dot3ControlInUnknownOpcodes), + RTL8365MB_MAKE_MIB_COUNTER(12, 2, etherStatsFragments), + RTL8365MB_MAKE_MIB_COUNTER(14, 2, etherStatsJabbers), + RTL8365MB_MAKE_MIB_COUNTER(16, 2, ifInUcastPkts), + RTL8365MB_MAKE_MIB_COUNTER(18, 2, etherStatsDropEvents), + RTL8365MB_MAKE_MIB_COUNTER(20, 2, ifInMulticastPkts), + RTL8365MB_MAKE_MIB_COUNTER(22, 2, ifInBroadcastPkts), + RTL8365MB_MAKE_MIB_COUNTER(24, 2, inMldChecksumError), + RTL8365MB_MAKE_MIB_COUNTER(26, 2, inIgmpChecksumError), + RTL8365MB_MAKE_MIB_COUNTER(28, 2, inMldSpecificQuery), + RTL8365MB_MAKE_MIB_COUNTER(30, 2, inMldGeneralQuery), + RTL8365MB_MAKE_MIB_COUNTER(32, 2, inIgmpSpecificQuery), + RTL8365MB_MAKE_MIB_COUNTER(34, 2, inIgmpGeneralQuery), + RTL8365MB_MAKE_MIB_COUNTER(36, 2, inMldLeaves), + RTL8365MB_MAKE_MIB_COUNTER(38, 2, inIgmpLeaves), + RTL8365MB_MAKE_MIB_COUNTER(40, 4, etherStatsOctets), + RTL8365MB_MAKE_MIB_COUNTER(44, 2, etherStatsUnderSizePkts), + RTL8365MB_MAKE_MIB_COUNTER(46, 2, etherOversizeStats), + RTL8365MB_MAKE_MIB_COUNTER(48, 2, etherStatsPkts64Octets), + RTL8365MB_MAKE_MIB_COUNTER(50, 2, etherStatsPkts65to127Octets), + RTL8365MB_MAKE_MIB_COUNTER(52, 2, etherStatsPkts128to255Octets), + RTL8365MB_MAKE_MIB_COUNTER(54, 2, etherStatsPkts256to511Octets), + RTL8365MB_MAKE_MIB_COUNTER(56, 2, etherStatsPkts512to1023Octets), + RTL8365MB_MAKE_MIB_COUNTER(58, 2, etherStatsPkts1024to1518Octets), + RTL8365MB_MAKE_MIB_COUNTER(60, 4, ifOutOctets), + RTL8365MB_MAKE_MIB_COUNTER(64, 2, dot3StatsSingleCollisionFrames), + RTL8365MB_MAKE_MIB_COUNTER(66, 2, dot3StatsMultipleCollisionFrames), + RTL8365MB_MAKE_MIB_COUNTER(68, 2, dot3StatsDeferredTransmissions), + RTL8365MB_MAKE_MIB_COUNTER(70, 2, dot3StatsLateCollisions), + RTL8365MB_MAKE_MIB_COUNTER(72, 2, etherStatsCollisions), + RTL8365MB_MAKE_MIB_COUNTER(74, 2, dot3StatsExcessiveCollisions), + RTL8365MB_MAKE_MIB_COUNTER(76, 2, dot3OutPauseFrames), + RTL8365MB_MAKE_MIB_COUNTER(78, 2, ifOutDiscards), + RTL8365MB_MAKE_MIB_COUNTER(80, 2, dot1dTpPortInDiscards), + RTL8365MB_MAKE_MIB_COUNTER(82, 2, ifOutUcastPkts), + RTL8365MB_MAKE_MIB_COUNTER(84, 2, ifOutMulticastPkts), + RTL8365MB_MAKE_MIB_COUNTER(86, 2, ifOutBroadcastPkts), + RTL8365MB_MAKE_MIB_COUNTER(88, 2, outOampduPkts), + RTL8365MB_MAKE_MIB_COUNTER(90, 2, inOampduPkts), + RTL8365MB_MAKE_MIB_COUNTER(92, 4, inIgmpJoinsSuccess), + RTL8365MB_MAKE_MIB_COUNTER(96, 2, inIgmpJoinsFail), + RTL8365MB_MAKE_MIB_COUNTER(98, 2, inMldJoinsSuccess), + RTL8365MB_MAKE_MIB_COUNTER(100, 2, inMldJoinsFail), + RTL8365MB_MAKE_MIB_COUNTER(102, 2, inReportSuppressionDrop), + RTL8365MB_MAKE_MIB_COUNTER(104, 2, inLeaveSuppressionDrop), + RTL8365MB_MAKE_MIB_COUNTER(106, 2, outIgmpReports), + RTL8365MB_MAKE_MIB_COUNTER(108, 2, outIgmpLeaves), + RTL8365MB_MAKE_MIB_COUNTER(110, 2, outIgmpGeneralQuery), + RTL8365MB_MAKE_MIB_COUNTER(112, 2, outIgmpSpecificQuery), + RTL8365MB_MAKE_MIB_COUNTER(114, 2, outMldReports), + RTL8365MB_MAKE_MIB_COUNTER(116, 2, outMldLeaves), + RTL8365MB_MAKE_MIB_COUNTER(118, 2, outMldGeneralQuery), + RTL8365MB_MAKE_MIB_COUNTER(120, 2, outMldSpecificQuery), + RTL8365MB_MAKE_MIB_COUNTER(122, 2, inKnownMulticastPkts), +}; + +static_assert(ARRAY_SIZE(rtl8365mb_mib_counters) =3D=3D RTL8365MB_MIB_END); + +struct rtl8365mb_jam_tbl_entry { + u16 reg; + u16 val; +}; + +/* Lifted from the vendor driver sources */ +static const struct rtl8365mb_jam_tbl_entry rtl8365mb_init_jam_8365mb_vc[]= =3D { + { 0x13EB, 0x15BB }, { 0x1303, 0x06D6 }, { 0x1304, 0x0700 }, + { 0x13E2, 0x003F }, { 0x13F9, 0x0090 }, { 0x121E, 0x03CA }, + { 0x1233, 0x0352 }, { 0x1237, 0x00A0 }, { 0x123A, 0x0030 }, + { 0x1239, 0x0084 }, { 0x0301, 0x1000 }, { 0x1349, 0x001F }, + { 0x18E0, 0x4004 }, { 0x122B, 0x241C }, { 0x1305, 0xC000 }, + { 0x13F0, 0x0000 }, +}; + +static const struct rtl8365mb_jam_tbl_entry rtl8365mb_init_jam_common[] = =3D { + { 0x1200, 0x7FCB }, { 0x0884, 0x0003 }, { 0x06EB, 0x0001 }, + { 0x03Fa, 0x0007 }, { 0x08C8, 0x00C0 }, { 0x0A30, 0x020E }, + { 0x0800, 0x0000 }, { 0x0802, 0x0000 }, { 0x09DA, 0x0013 }, + { 0x1D32, 0x0002 }, +}; + +enum rtl8365mb_stp_state { + RTL8365MB_STP_STATE_DISABLED =3D 0, + RTL8365MB_STP_STATE_BLOCKING =3D 1, + RTL8365MB_STP_STATE_LEARNING =3D 2, + RTL8365MB_STP_STATE_FORWARDING =3D 3, +}; + +enum rtl8365mb_cpu_insert { + RTL8365MB_CPU_INSERT_TO_ALL =3D 0, + RTL8365MB_CPU_INSERT_TO_TRAPPING =3D 1, + RTL8365MB_CPU_INSERT_TO_NONE =3D 2, +}; + +enum rtl8365mb_cpu_position { + RTL8365MB_CPU_POS_AFTER_SA =3D 0, + RTL8365MB_CPU_POS_BEFORE_CRC =3D 1, +}; + +enum rtl8365mb_cpu_format { + RTL8365MB_CPU_FORMAT_8BYTES =3D 0, + RTL8365MB_CPU_FORMAT_4BYTES =3D 1, +}; + +enum rtl8365mb_cpu_rxlen { + RTL8365MB_CPU_RXLEN_72BYTES =3D 0, + RTL8365MB_CPU_RXLEN_64BYTES =3D 1, +}; + +/** + * struct rtl8365mb_cpu - CPU port configuration + * @enable: enable/disable hardware insertion of CPU tag in switch->CPU fr= ames + * @mask: port mask of ports that parse should parse CPU tags + * @trap_port: forward trapped frames to this port + * @insert: CPU tag insertion mode in switch->CPU frames + * @position: position of CPU tag in frame + * @rx_length: minimum CPU RX length + * @format: CPU tag format + * + * Represents the CPU tagging and CPU port configuration of the switch. Th= ese + * settings are configurable at runtime. + */ +struct rtl8365mb_cpu { + bool enable; + u32 mask; + u32 trap_port; + enum rtl8365mb_cpu_insert insert; + enum rtl8365mb_cpu_position position; + enum rtl8365mb_cpu_rxlen rx_length; + enum rtl8365mb_cpu_format format; +}; + +/** + * struct rtl8365mb_port - private per-port data + * @smi: pointer to parent realtek_smi data + * @index: DSA port index, same as dsa_port::index + * @stats: link statistics populated by rtl8365mb_stats_poll, ready for at= omic + * access via rtl8365mb_get_stats64 + * @stats_lock: protect the stats structure during read/update + * @mib_work: delayed work for polling MIB counters + */ +struct rtl8365mb_port { + struct realtek_smi *smi; + unsigned int index; + struct rtnl_link_stats64 stats; + spinlock_t stats_lock; + struct delayed_work mib_work; +}; + +/** + * struct rtl8365mb - private chip-specific driver data + * @smi: pointer to parent realtek_smi data + * @irq: registered IRQ or zero + * @chip_id: chip identifier + * @chip_ver: chip silicon revision + * @port_mask: mask of all ports + * @learn_limit_max: maximum number of L2 addresses the chip can learn + * @cpu: CPU tagging and CPU port configuration for this chip + * @mib_lock: prevent concurrent reads of MIB counters + * @ports: per-port data + * @jam_table: chip-specific initialization jam table + * @jam_size: size of the chip's jam table + * + * Private data for this driver. + */ +struct rtl8365mb { + struct realtek_smi *smi; + int irq; + u32 chip_id; + u32 chip_ver; + u32 port_mask; + u32 learn_limit_max; + struct rtl8365mb_cpu cpu; + struct mutex mib_lock; + struct rtl8365mb_port ports[RTL8365MB_MAX_NUM_PORTS]; + const struct rtl8365mb_jam_tbl_entry *jam_table; + size_t jam_size; +}; + +static int rtl8365mb_phy_poll_busy(struct realtek_smi *smi) +{ + u32 val; + + return regmap_read_poll_timeout(smi->map, + RTL8365MB_INDIRECT_ACCESS_STATUS_REG, + val, !val, 10, 100); +} + +static int rtl8365mb_phy_ocp_prepare(struct realtek_smi *smi, int phy, + u32 ocp_addr) +{ + u32 val; + int ret; + + /* Set OCP prefix */ + val =3D FIELD_GET(RTL8365MB_PHY_OCP_ADDR_PREFIX_MASK, ocp_addr); + ret =3D regmap_update_bits( + smi->map, RTL8365MB_GPHY_OCP_MSB_0_REG, + RTL8365MB_GPHY_OCP_MSB_0_CFG_CPU_OCPADR_MASK, + FIELD_PREP(RTL8365MB_GPHY_OCP_MSB_0_CFG_CPU_OCPADR_MASK, val)); + if (ret) + return ret; + + /* Set PHY register address */ + val =3D RTL8365MB_PHY_BASE; + val |=3D FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_ADDRESS_PHYNUM_MASK, phy); + val |=3D FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_ADDRESS_OCPADR_5_1_MASK, + ocp_addr >> 1); + val |=3D FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_ADDRESS_OCPADR_9_6_MASK, + ocp_addr >> 6); + ret =3D regmap_write(smi->map, RTL8365MB_INDIRECT_ACCESS_ADDRESS_REG, + val); + if (ret) + return ret; + + return 0; +} + +static int rtl8365mb_phy_ocp_read(struct realtek_smi *smi, int phy, + u32 ocp_addr, u16 *data) +{ + u32 val; + int ret; + + ret =3D rtl8365mb_phy_poll_busy(smi); + if (ret) + return ret; + + ret =3D rtl8365mb_phy_ocp_prepare(smi, phy, ocp_addr); + if (ret) + return ret; + + /* Execute read operation */ + val =3D FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_MASK, + RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_VALUE) | + FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_RW_MASK, + RTL8365MB_INDIRECT_ACCESS_CTRL_RW_READ); + ret =3D regmap_write(smi->map, RTL8365MB_INDIRECT_ACCESS_CTRL_REG, val); + if (ret) + return ret; + + ret =3D rtl8365mb_phy_poll_busy(smi); + if (ret) + return ret; + + /* Get PHY register data */ + ret =3D regmap_read(smi->map, RTL8365MB_INDIRECT_ACCESS_READ_DATA_REG, + &val); + if (ret) + return ret; + + *data =3D val & 0xFFFF; + + return 0; +} + +static int rtl8365mb_phy_ocp_write(struct realtek_smi *smi, int phy, + u32 ocp_addr, u16 data) +{ + u32 val; + int ret; + + ret =3D rtl8365mb_phy_poll_busy(smi); + if (ret) + return ret; + + ret =3D rtl8365mb_phy_ocp_prepare(smi, phy, ocp_addr); + if (ret) + return ret; + + /* Set PHY register data */ + ret =3D regmap_write(smi->map, RTL8365MB_INDIRECT_ACCESS_WRITE_DATA_REG, + data); + if (ret) + return ret; + + /* Execute write operation */ + val =3D FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_MASK, + RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_VALUE) | + FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_RW_MASK, + RTL8365MB_INDIRECT_ACCESS_CTRL_RW_WRITE); + ret =3D regmap_write(smi->map, RTL8365MB_INDIRECT_ACCESS_CTRL_REG, val); + if (ret) + return ret; + + ret =3D rtl8365mb_phy_poll_busy(smi); + if (ret) + return ret; + + return 0; +} + +static int rtl8365mb_phy_read(struct realtek_smi *smi, int phy, int regnum) +{ + u32 ocp_addr; + u16 val; + int ret; + + if (phy > RTL8365MB_PHYADDRMAX) + return -EINVAL; + + if (regnum > RTL8365MB_PHYREGMAX) + return -EINVAL; + + ocp_addr =3D RTL8365MB_PHY_OCP_ADDR_PHYREG_BASE + regnum * 2; + + ret =3D rtl8365mb_phy_ocp_read(smi, phy, ocp_addr, &val); + if (ret) { + dev_err(smi->dev, + "failed to read PHY%d reg %02x @ %04x, ret %d\n", phy, + regnum, ocp_addr, ret); + return ret; + } + + dev_dbg(smi->dev, "read PHY%d register 0x%02x @ %04x, val <- %04x\n", + phy, regnum, ocp_addr, val); + + return val; +} + +static int rtl8365mb_phy_write(struct realtek_smi *smi, int phy, int regnu= m, + u16 val) +{ + u32 ocp_addr; + int ret; + + if (phy > RTL8365MB_PHYADDRMAX) + return -EINVAL; + + if (regnum > RTL8365MB_PHYREGMAX) + return -EINVAL; + + ocp_addr =3D RTL8365MB_PHY_OCP_ADDR_PHYREG_BASE + regnum * 2; + + ret =3D rtl8365mb_phy_ocp_write(smi, phy, ocp_addr, val); + if (ret) { + dev_err(smi->dev, + "failed to write PHY%d reg %02x @ %04x, ret %d\n", phy, + regnum, ocp_addr, ret); + return ret; + } + + dev_dbg(smi->dev, "write PHY%d register 0x%02x @ %04x, val -> %04x\n", + phy, regnum, ocp_addr, val); + + return 0; +} + +static enum dsa_tag_protocol +rtl8365mb_get_tag_protocol(struct dsa_switch *ds, int port, + enum dsa_tag_protocol mp) +{ + return DSA_TAG_PROTO_RTL8_4; +} + +static int rtl8365mb_ext_config_rgmii(struct realtek_smi *smi, int port, + phy_interface_t interface) +{ + struct device_node *dn; + struct dsa_port *dp; + int tx_delay =3D 0; + int rx_delay =3D 0; + int ext_port; + u32 val; + int ret; + + if (port =3D=3D smi->cpu_port) { + ext_port =3D 1; + } else { + dev_err(smi->dev, "only one EXT port is currently supported\n"); + return -EINVAL; + } + + dp =3D dsa_to_port(smi->ds, port); + dn =3D dp->dn; + + /* Set the RGMII TX/RX delay + * + * The Realtek vendor driver indicates the following possible + * configuration settings: + * + * TX delay: + * 0 =3D no delay, 1 =3D 2 ns delay + * RX delay: + * 0 =3D no delay, 7 =3D maximum delay + * Each step is approximately 0.3 ns, so the maximum delay is about + * 2.1 ns. + * + * The vendor driver also states that this must be configured *before* + * forcing the external interface into a particular mode, which is done + * in the rtl8365mb_phylink_mac_link_{up,down} functions. + * + * Only configure an RGMII TX (resp. RX) delay if the + * tx-internal-delay-ps (resp. rx-internal-delay-ps) OF property is + * specified. We ignore the detail of the RGMII interface mode + * (RGMII_{RXID, TXID, etc.}), as this is considered to be a PHY-only + * property. + */ + if (!of_property_read_u32(dn, "tx-internal-delay-ps", &val)) { + val =3D val / 1000; /* convert to ns */ + + if (val =3D=3D 0 || val =3D=3D 2) + tx_delay =3D val / 2; + else + dev_warn(smi->dev, + "EXT port TX delay must be 0 or 2 ns\n"); + } + + if (!of_property_read_u32(dn, "rx-internal-delay-ps", &val)) { + val =3D DIV_ROUND_CLOSEST(val, 300); /* convert to 0.3 ns step */ + + if (val <=3D 7) + rx_delay =3D val; + else + dev_warn(smi->dev, + "EXT port RX delay must be 0 to 2.1 ns\n"); + } + + ret =3D regmap_update_bits( + smi->map, RTL8365MB_EXT_RGMXF_REG(ext_port), + RTL8365MB_EXT_RGMXF_TXDELAY_MASK | + RTL8365MB_EXT_RGMXF_RXDELAY_MASK, + FIELD_PREP(RTL8365MB_EXT_RGMXF_TXDELAY_MASK, tx_delay) | + FIELD_PREP(RTL8365MB_EXT_RGMXF_RXDELAY_MASK, rx_delay)); + if (ret) + return ret; + + ret =3D regmap_update_bits( + smi->map, RTL8365MB_DIGITAL_INTERFACE_SELECT_REG(ext_port), + RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(ext_port), + RTL8365MB_EXT_PORT_MODE_RGMII + << RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET( + ext_port)); + if (ret) + return ret; + + return 0; +} + +static int rtl8365mb_ext_config_forcemode(struct realtek_smi *smi, int por= t, + bool link, int speed, int duplex, + bool tx_pause, bool rx_pause) +{ + u32 r_tx_pause; + u32 r_rx_pause; + u32 r_duplex; + u32 r_speed; + u32 r_link; + int ext_port; + int val; + int ret; + + if (port =3D=3D smi->cpu_port) { + ext_port =3D 1; + } else { + dev_err(smi->dev, "only one EXT port is currently supported\n"); + return -EINVAL; + } + + if (link) { + /* Force the link up with the desired configuration */ + r_link =3D 1; + r_rx_pause =3D rx_pause ? 1 : 0; + r_tx_pause =3D tx_pause ? 1 : 0; + + if (speed =3D=3D SPEED_1000) { + r_speed =3D RTL8365MB_PORT_SPEED_1000M; + } else if (speed =3D=3D SPEED_100) { + r_speed =3D RTL8365MB_PORT_SPEED_100M; + } else if (speed =3D=3D SPEED_10) { + r_speed =3D RTL8365MB_PORT_SPEED_10M; + } else { + dev_err(smi->dev, "unsupported port speed %s\n", + phy_speed_to_str(speed)); + return -EINVAL; + } + + if (duplex =3D=3D DUPLEX_FULL) { + r_duplex =3D 1; + } else if (duplex =3D=3D DUPLEX_HALF) { + r_duplex =3D 0; + } else { + dev_err(smi->dev, "unsupported duplex %s\n", + phy_duplex_to_str(duplex)); + return -EINVAL; + } + } else { + /* Force the link down and reset any programmed configuration */ + r_link =3D 0; + r_tx_pause =3D 0; + r_rx_pause =3D 0; + r_speed =3D 0; + r_duplex =3D 0; + } + + val =3D FIELD_PREP(RTL8365MB_DIGITAL_INTERFACE_FORCE_EN_MASK, 1) | + FIELD_PREP(RTL8365MB_DIGITAL_INTERFACE_FORCE_TXPAUSE_MASK, + r_tx_pause) | + FIELD_PREP(RTL8365MB_DIGITAL_INTERFACE_FORCE_RXPAUSE_MASK, + r_rx_pause) | + FIELD_PREP(RTL8365MB_DIGITAL_INTERFACE_FORCE_LINK_MASK, r_link) | + FIELD_PREP(RTL8365MB_DIGITAL_INTERFACE_FORCE_DUPLEX_MASK, + r_duplex) | + FIELD_PREP(RTL8365MB_DIGITAL_INTERFACE_FORCE_SPEED_MASK, r_speed); + ret =3D regmap_write(smi->map, + RTL8365MB_DIGITAL_INTERFACE_FORCE_REG(ext_port), + val); + if (ret) + return ret; + + return 0; +} + +static bool rtl8365mb_phy_mode_supported(struct dsa_switch *ds, int port, + phy_interface_t interface) +{ + if (dsa_is_user_port(ds, port) && + (interface =3D=3D PHY_INTERFACE_MODE_NA || + interface =3D=3D PHY_INTERFACE_MODE_INTERNAL)) + /* Internal PHY */ + return true; + else if (dsa_is_cpu_port(ds, port) && + phy_interface_mode_is_rgmii(interface)) + /* Extension MAC */ + return true; + + return false; +} + +static void rtl8365mb_phylink_validate(struct dsa_switch *ds, int port, + unsigned long *supported, + struct phylink_link_state *state) +{ + struct realtek_smi *smi =3D ds->priv; + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) =3D { 0 }; + + /* include/linux/phylink.h says: + * When @state->interface is %PHY_INTERFACE_MODE_NA, phylink + * expects the MAC driver to return all supported link modes. + */ + if (state->interface !=3D PHY_INTERFACE_MODE_NA && + !rtl8365mb_phy_mode_supported(ds, port, state->interface)) { + dev_err(smi->dev, "phy mode %s is unsupported on port %d\n", + phy_modes(state->interface), port); + linkmode_zero(supported); + return; + } + + phylink_set_port_modes(mask); + + phylink_set(mask, Autoneg); + phylink_set(mask, Pause); + phylink_set(mask, Asym_Pause); + + phylink_set(mask, 10baseT_Half); + phylink_set(mask, 10baseT_Full); + phylink_set(mask, 100baseT_Half); + phylink_set(mask, 100baseT_Full); + phylink_set(mask, 1000baseT_Full); + + linkmode_and(supported, supported, mask); + linkmode_and(state->advertising, state->advertising, mask); +} + +static void rtl8365mb_phylink_mac_config(struct dsa_switch *ds, int port, + unsigned int mode, + const struct phylink_link_state *state) +{ + struct realtek_smi *smi =3D ds->priv; + int ret; + + if (!rtl8365mb_phy_mode_supported(ds, port, state->interface)) { + dev_err(smi->dev, "phy mode %s is unsupported on port %d\n", + phy_modes(state->interface), port); + return; + } + + if (mode !=3D MLO_AN_PHY && mode !=3D MLO_AN_FIXED) { + dev_err(smi->dev, + "port %d supports only conventional PHY or fixed-link\n", + port); + return; + } + + if (phy_interface_mode_is_rgmii(state->interface)) { + ret =3D rtl8365mb_ext_config_rgmii(smi, port, state->interface); + if (ret) + dev_err(smi->dev, + "failed to configure RGMII mode on port %d: %d\n", + port, ret); + return; + } + + /* TODO: Implement MII and RMII modes, which the RTL8365MB-VC also + * supports + */ +} + +static void rtl8365mb_phylink_mac_link_down(struct dsa_switch *ds, int por= t, + unsigned int mode, + phy_interface_t interface) +{ + struct realtek_smi *smi =3D ds->priv; + struct rtl8365mb_port *p; + struct rtl8365mb *mb; + int ret; + + mb =3D smi->chip_data; + p =3D &mb->ports[port]; + cancel_delayed_work_sync(&p->mib_work); + + if (phy_interface_mode_is_rgmii(interface)) { + ret =3D rtl8365mb_ext_config_forcemode(smi, port, false, 0, 0, + false, false); + if (ret) + dev_err(smi->dev, + "failed to reset forced mode on port %d: %d\n", + port, ret); + + return; + } +} + +static void rtl8365mb_phylink_mac_link_up(struct dsa_switch *ds, int port, + unsigned int mode, + phy_interface_t interface, + struct phy_device *phydev, int speed, + int duplex, bool tx_pause, + bool rx_pause) +{ + struct realtek_smi *smi =3D ds->priv; + struct rtl8365mb_port *p; + struct rtl8365mb *mb; + int ret; + + mb =3D smi->chip_data; + p =3D &mb->ports[port]; + schedule_delayed_work(&p->mib_work, 0); + + if (phy_interface_mode_is_rgmii(interface)) { + ret =3D rtl8365mb_ext_config_forcemode(smi, port, true, speed, + duplex, tx_pause, + rx_pause); + if (ret) + dev_err(smi->dev, + "failed to force mode on port %d: %d\n", port, + ret); + + return; + } +} + +static void rtl8365mb_port_stp_state_set(struct dsa_switch *ds, int port, + u8 state) +{ + struct realtek_smi *smi =3D ds->priv; + enum rtl8365mb_stp_state val; + int msti =3D 0; + + switch (state) { + case BR_STATE_DISABLED: + val =3D RTL8365MB_STP_STATE_DISABLED; + break; + case BR_STATE_BLOCKING: + case BR_STATE_LISTENING: + val =3D RTL8365MB_STP_STATE_BLOCKING; + break; + case BR_STATE_LEARNING: + val =3D RTL8365MB_STP_STATE_LEARNING; + break; + case BR_STATE_FORWARDING: + val =3D RTL8365MB_STP_STATE_FORWARDING; + break; + default: + dev_err(smi->dev, "invalid STP state: %u\n", state); + return; + } + + regmap_update_bits(smi->map, RTL8365MB_MSTI_CTRL_REG(msti, port), + RTL8365MB_MSTI_CTRL_PORT_STATE_MASK(port), + val << RTL8365MB_MSTI_CTRL_PORT_STATE_OFFSET(port)); +} + +static int rtl8365mb_port_set_learning(struct realtek_smi *smi, int port, + bool enable) +{ + struct rtl8365mb *mb =3D smi->chip_data; + + /* Enable/disable learning by limiting the number of L2 addresses the + * port can learn. Realtek documentation states that a limit of zero + * disables learning. When enabling learning, set it to the chip's + * maximum. + */ + return regmap_write(smi->map, RTL8365MB_LUT_PORT_LEARN_LIMIT_REG(port), + enable ? mb->learn_limit_max : 0); +} + +static int rtl8365mb_port_set_isolation(struct realtek_smi *smi, int port, + u32 mask) +{ + return regmap_write(smi->map, RTL8365MB_PORT_ISOLATION_REG(port), mask); +} + +static int rtl8365mb_mib_counter_read(struct realtek_smi *smi, int port, + u32 offset, u32 length, u64 *mibvalue) +{ + u64 tmpvalue =3D 0; + u32 val; + int ret; + int i; + + /* The MIB address is an SRAM address. We request a particular address + * and then poll the control register before reading the value from some + * counter registers. + */ + ret =3D regmap_write(smi->map, RTL8365MB_MIB_ADDRESS_REG, + RTL8365MB_MIB_ADDRESS(port, offset)); + if (ret) + return ret; + + /* Poll for completion */ + ret =3D regmap_read_poll_timeout(smi->map, RTL8365MB_MIB_CTRL0_REG, val, + !(val & RTL8365MB_MIB_CTRL0_BUSY_MASK), + 10, 100); + if (ret) + return ret; + + /* Presumably this indicates a MIB counter read failure */ + if (val & RTL8365MB_MIB_CTRL0_RESET_MASK) + return -EIO; + + /* There are four MIB counter registers each holding a 16 bit word of a + * MIB counter. Depending on the offset, we should read from the upper + * two or lower two registers. In case the MIB counter is 4 words, we + * read from all four registers. + */ + if (length =3D=3D 4) + offset =3D 3; + else + offset =3D (offset + 1) % 4; + + /* Read the MIB counter 16 bits at a time */ + for (i =3D 0; i < length; i++) { + ret =3D regmap_read(smi->map, + RTL8365MB_MIB_COUNTER_REG(offset - i), &val); + if (ret) + return ret; + + tmpvalue =3D ((tmpvalue) << 16) | (val & 0xFFFF); + } + + /* Only commit the result if no error occurred */ + *mibvalue =3D tmpvalue; + + return 0; +} + +static void rtl8365mb_get_ethtool_stats(struct dsa_switch *ds, int port, u= 64 *data) +{ + struct realtek_smi *smi =3D ds->priv; + struct rtl8365mb *mb; + int ret; + int i; + + mb =3D smi->chip_data; + + mutex_lock(&mb->mib_lock); + for (i =3D 0; i < RTL8365MB_MIB_END; i++) { + struct rtl8365mb_mib_counter *mib =3D &rtl8365mb_mib_counters[i]; + + ret =3D rtl8365mb_mib_counter_read(smi, port, mib->offset, + mib->length, &data[i]); + if (ret) { + dev_err(smi->dev, + "failed to read port %d counters: %d\n", port, + ret); + break; + } + } + mutex_unlock(&mb->mib_lock); +} + +static void rtl8365mb_get_strings(struct dsa_switch *ds, int port, u32 str= ingset, u8 *data) +{ + int i; + + if (stringset !=3D ETH_SS_STATS) + return; + + for (i =3D 0; i < RTL8365MB_MIB_END; i++) { + struct rtl8365mb_mib_counter *mib =3D &rtl8365mb_mib_counters[i]; + + strncpy(data + i * ETH_GSTRING_LEN, mib->name, ETH_GSTRING_LEN); + } +} + +static int rtl8365mb_get_sset_count(struct dsa_switch *ds, int port, int s= set) +{ + if (sset !=3D ETH_SS_STATS) + return -EOPNOTSUPP; + + return RTL8365MB_MIB_END; +} + +static void rtl8365mb_get_phy_stats(struct dsa_switch *ds, int port, + struct ethtool_eth_phy_stats *phy_stats) +{ + struct realtek_smi *smi =3D ds->priv; + struct rtl8365mb_mib_counter *mib; + struct rtl8365mb *mb; + + mb =3D smi->chip_data; + mib =3D &rtl8365mb_mib_counters[RTL8365MB_MIB_dot3StatsSymbolErrors]; + + mutex_lock(&mb->mib_lock); + rtl8365mb_mib_counter_read(smi, port, mib->offset, mib->length, + &phy_stats->SymbolErrorDuringCarrier); + mutex_unlock(&mb->mib_lock); +} + +static void rtl8365mb_get_mac_stats(struct dsa_switch *ds, int port, + struct ethtool_eth_mac_stats *mac_stats) +{ + u64 cnt[RTL8365MB_MIB_END] =3D { + [RTL8365MB_MIB_ifOutOctets] =3D 1, + [RTL8365MB_MIB_ifOutUcastPkts] =3D 1, + [RTL8365MB_MIB_ifOutMulticastPkts] =3D 1, + [RTL8365MB_MIB_ifOutBroadcastPkts] =3D 1, + [RTL8365MB_MIB_dot3OutPauseFrames] =3D 1, + [RTL8365MB_MIB_ifOutDiscards] =3D 1, + [RTL8365MB_MIB_ifInOctets] =3D 1, + [RTL8365MB_MIB_ifInUcastPkts] =3D 1, + [RTL8365MB_MIB_ifInMulticastPkts] =3D 1, + [RTL8365MB_MIB_ifInBroadcastPkts] =3D 1, + [RTL8365MB_MIB_dot3InPauseFrames] =3D 1, + [RTL8365MB_MIB_dot3StatsSingleCollisionFrames] =3D 1, + [RTL8365MB_MIB_dot3StatsMultipleCollisionFrames] =3D 1, + [RTL8365MB_MIB_dot3StatsFCSErrors] =3D 1, + [RTL8365MB_MIB_dot3StatsDeferredTransmissions] =3D 1, + [RTL8365MB_MIB_dot3StatsLateCollisions] =3D 1, + [RTL8365MB_MIB_dot3StatsExcessiveCollisions] =3D 1, + + }; + struct realtek_smi *smi =3D ds->priv; + struct rtl8365mb *mb; + int ret; + int i; + + mb =3D smi->chip_data; + + mutex_lock(&mb->mib_lock); + for (i =3D 0; i < RTL8365MB_MIB_END; i++) { + struct rtl8365mb_mib_counter *mib =3D &rtl8365mb_mib_counters[i]; + + /* Only fetch required MIB counters (marked =3D 1 above) */ + if (!cnt[i]) + continue; + + ret =3D rtl8365mb_mib_counter_read(smi, port, mib->offset, + mib->length, &cnt[i]); + if (ret) + break; + } + mutex_unlock(&mb->mib_lock); + + /* The RTL8365MB-VC exposes MIB objects, which we have to translate into + * IEEE 802.3 Managed Objects. This is not always completely faithful, + * but we try out best. See RFC 3635 for a detailed treatment of the + * subject. + */ + + mac_stats->FramesTransmittedOK =3D cnt[RTL8365MB_MIB_ifOutUcastPkts] + + cnt[RTL8365MB_MIB_ifOutMulticastPkts] + + cnt[RTL8365MB_MIB_ifOutBroadcastPkts] + + cnt[RTL8365MB_MIB_dot3OutPauseFrames] - + cnt[RTL8365MB_MIB_ifOutDiscards]; + mac_stats->SingleCollisionFrames =3D + cnt[RTL8365MB_MIB_dot3StatsSingleCollisionFrames]; + mac_stats->MultipleCollisionFrames =3D + cnt[RTL8365MB_MIB_dot3StatsMultipleCollisionFrames]; + mac_stats->FramesReceivedOK =3D cnt[RTL8365MB_MIB_ifInUcastPkts] + + cnt[RTL8365MB_MIB_ifInMulticastPkts] + + cnt[RTL8365MB_MIB_ifInBroadcastPkts] + + cnt[RTL8365MB_MIB_dot3InPauseFrames]; + mac_stats->FrameCheckSequenceErrors =3D + cnt[RTL8365MB_MIB_dot3StatsFCSErrors]; + mac_stats->OctetsTransmittedOK =3D cnt[RTL8365MB_MIB_ifOutOctets] - + 18 * mac_stats->FramesTransmittedOK; + mac_stats->FramesWithDeferredXmissions =3D + cnt[RTL8365MB_MIB_dot3StatsDeferredTransmissions]; + mac_stats->LateCollisions =3D cnt[RTL8365MB_MIB_dot3StatsLateCollisions]; + mac_stats->FramesAbortedDueToXSColls =3D + cnt[RTL8365MB_MIB_dot3StatsExcessiveCollisions]; + mac_stats->OctetsReceivedOK =3D cnt[RTL8365MB_MIB_ifInOctets] - + 18 * mac_stats->FramesReceivedOK; + mac_stats->MulticastFramesXmittedOK =3D + cnt[RTL8365MB_MIB_ifOutMulticastPkts]; + mac_stats->BroadcastFramesXmittedOK =3D + cnt[RTL8365MB_MIB_ifOutBroadcastPkts]; + mac_stats->MulticastFramesReceivedOK =3D + cnt[RTL8365MB_MIB_ifInMulticastPkts]; + mac_stats->BroadcastFramesReceivedOK =3D + cnt[RTL8365MB_MIB_ifInBroadcastPkts]; +} + +static void rtl8365mb_get_ctrl_stats(struct dsa_switch *ds, int port, + struct ethtool_eth_ctrl_stats *ctrl_stats) +{ + struct realtek_smi *smi =3D ds->priv; + struct rtl8365mb_mib_counter *mib; + struct rtl8365mb *mb; + + mb =3D smi->chip_data; + mib =3D &rtl8365mb_mib_counters[RTL8365MB_MIB_dot3ControlInUnknownOpcodes= ]; + + mutex_lock(&mb->mib_lock); + rtl8365mb_mib_counter_read(smi, port, mib->offset, mib->length, + &ctrl_stats->UnsupportedOpcodesReceived); + mutex_unlock(&mb->mib_lock); +} + +static void rtl8365mb_stats_update(struct realtek_smi *smi, int port) +{ + u64 cnt[RTL8365MB_MIB_END] =3D { + [RTL8365MB_MIB_ifOutOctets] =3D 1, + [RTL8365MB_MIB_ifOutUcastPkts] =3D 1, + [RTL8365MB_MIB_ifOutMulticastPkts] =3D 1, + [RTL8365MB_MIB_ifOutBroadcastPkts] =3D 1, + [RTL8365MB_MIB_ifOutDiscards] =3D 1, + [RTL8365MB_MIB_ifInOctets] =3D 1, + [RTL8365MB_MIB_ifInUcastPkts] =3D 1, + [RTL8365MB_MIB_ifInMulticastPkts] =3D 1, + [RTL8365MB_MIB_ifInBroadcastPkts] =3D 1, + [RTL8365MB_MIB_etherStatsDropEvents] =3D 1, + [RTL8365MB_MIB_etherStatsCollisions] =3D 1, + [RTL8365MB_MIB_etherStatsFragments] =3D 1, + [RTL8365MB_MIB_etherStatsJabbers] =3D 1, + [RTL8365MB_MIB_dot3StatsFCSErrors] =3D 1, + [RTL8365MB_MIB_dot3StatsLateCollisions] =3D 1, + }; + struct rtl8365mb *mb =3D smi->chip_data; + struct rtnl_link_stats64 *stats; + int ret; + int i; + + stats =3D &mb->ports[port].stats; + + mutex_lock(&mb->mib_lock); + for (i =3D 0; i < RTL8365MB_MIB_END; i++) { + struct rtl8365mb_mib_counter *c =3D &rtl8365mb_mib_counters[i]; + + /* Only fetch required MIB counters (marked =3D 1 above) */ + if (!cnt[i]) + continue; + + ret =3D rtl8365mb_mib_counter_read(smi, port, c->offset, + c->length, &cnt[i]); + if (ret) + break; + } + mutex_unlock(&mb->mib_lock); + + /* Don't update statistics if there was an error reading the counters */ + if (ret) + return; + + spin_lock(&mb->ports[port].stats_lock); + + stats->rx_packets =3D cnt[RTL8365MB_MIB_ifInUcastPkts] + + cnt[RTL8365MB_MIB_ifInMulticastPkts] + + cnt[RTL8365MB_MIB_ifInBroadcastPkts] - + cnt[RTL8365MB_MIB_ifOutDiscards]; + + stats->tx_packets =3D cnt[RTL8365MB_MIB_ifOutUcastPkts] + + cnt[RTL8365MB_MIB_ifOutMulticastPkts] + + cnt[RTL8365MB_MIB_ifOutBroadcastPkts]; + + /* if{In,Out}Octets includes FCS - remove it */ + stats->rx_bytes =3D cnt[RTL8365MB_MIB_ifInOctets] - 4 * stats->rx_packets; + stats->tx_bytes =3D + cnt[RTL8365MB_MIB_ifOutOctets] - 4 * stats->tx_packets; + + stats->rx_dropped =3D cnt[RTL8365MB_MIB_etherStatsDropEvents]; + stats->tx_dropped =3D cnt[RTL8365MB_MIB_ifOutDiscards]; + + stats->multicast =3D cnt[RTL8365MB_MIB_ifInMulticastPkts]; + stats->collisions =3D cnt[RTL8365MB_MIB_etherStatsCollisions]; + + stats->rx_length_errors =3D cnt[RTL8365MB_MIB_etherStatsFragments] + + cnt[RTL8365MB_MIB_etherStatsJabbers]; + stats->rx_crc_errors =3D cnt[RTL8365MB_MIB_dot3StatsFCSErrors]; + stats->rx_errors =3D stats->rx_length_errors + stats->rx_crc_errors; + + stats->tx_aborted_errors =3D cnt[RTL8365MB_MIB_ifOutDiscards]; + stats->tx_window_errors =3D cnt[RTL8365MB_MIB_dot3StatsLateCollisions]; + stats->tx_errors =3D stats->tx_aborted_errors + stats->tx_window_errors; + + spin_unlock(&mb->ports[port].stats_lock); +} + +static void rtl8365mb_stats_poll(struct work_struct *work) +{ + struct rtl8365mb_port *p =3D container_of(to_delayed_work(work), + struct rtl8365mb_port, + mib_work); + struct realtek_smi *smi =3D p->smi; + + rtl8365mb_stats_update(smi, p->index); + + schedule_delayed_work(&p->mib_work, RTL8365MB_STATS_INTERVAL_JIFFIES); +} + +static void rtl8365mb_get_stats64(struct dsa_switch *ds, int port, + struct rtnl_link_stats64 *s) +{ + struct realtek_smi *smi =3D ds->priv; + struct rtl8365mb_port *p; + struct rtl8365mb *mb; + + mb =3D smi->chip_data; + p =3D &mb->ports[port]; + + spin_lock(&p->stats_lock); + memcpy(s, &p->stats, sizeof(*s)); + spin_unlock(&p->stats_lock); +} + +static void rtl8365mb_stats_setup(struct realtek_smi *smi) +{ + struct rtl8365mb *mb =3D smi->chip_data; + int i; + + /* Per-chip global mutex to protect MIB counter access, since doing + * so requires accessing a series of registers in a particular order. + */ + mutex_init(&mb->mib_lock); + + for (i =3D 0; i < smi->num_ports; i++) { + struct rtl8365mb_port *p =3D &mb->ports[i]; + + if (dsa_is_unused_port(smi->ds, i)) + continue; + + /* Per-port spinlock to protect the stats64 data */ + spin_lock_init(&p->stats_lock); + + /* This work polls the MIB counters and keeps the stats64 data + * up-to-date. + */ + INIT_DELAYED_WORK(&p->mib_work, rtl8365mb_stats_poll); + } +} + +static void rtl8365mb_stats_teardown(struct realtek_smi *smi) +{ + struct rtl8365mb *mb =3D smi->chip_data; + int i; + + for (i =3D 0; i < smi->num_ports; i++) { + struct rtl8365mb_port *p =3D &mb->ports[i]; + + if (dsa_is_unused_port(smi->ds, i)) + continue; + + cancel_delayed_work_sync(&p->mib_work); + } +} + +static int rtl8365mb_get_and_clear_status_reg(struct realtek_smi *smi, u32= reg, + u32 *val) +{ + int ret; + + ret =3D regmap_read(smi->map, reg, val); + if (ret) + return ret; + + return regmap_write(smi->map, reg, *val); +} + +static irqreturn_t rtl8365mb_irq(int irq, void *data) +{ + struct realtek_smi *smi =3D data; + unsigned long line_changes =3D 0; + struct rtl8365mb *mb; + u32 stat; + int line; + int ret; + + mb =3D smi->chip_data; + + ret =3D rtl8365mb_get_and_clear_status_reg(smi, RTL8365MB_INTR_STATUS_REG, + &stat); + if (ret) + goto out_error; + + if (stat & RTL8365MB_INTR_LINK_CHANGE_MASK) { + u32 linkdown_ind; + u32 linkup_ind; + u32 val; + + ret =3D rtl8365mb_get_and_clear_status_reg( + smi, RTL8365MB_PORT_LINKUP_IND_REG, &val); + if (ret) + goto out_error; + + linkup_ind =3D FIELD_GET(RTL8365MB_PORT_LINKUP_IND_MASK, val); + + ret =3D rtl8365mb_get_and_clear_status_reg( + smi, RTL8365MB_PORT_LINKDOWN_IND_REG, &val); + if (ret) + goto out_error; + + linkdown_ind =3D FIELD_GET(RTL8365MB_PORT_LINKDOWN_IND_MASK, val); + + line_changes =3D (linkup_ind | linkdown_ind) & mb->port_mask; + } + + if (!line_changes) + goto out_none; + + for_each_set_bit(line, &line_changes, smi->num_ports) { + int child_irq =3D irq_find_mapping(smi->irqdomain, line); + + handle_nested_irq(child_irq); + } + + return IRQ_HANDLED; + +out_error: + dev_err(smi->dev, "failed to read interrupt status: %d\n", ret); + +out_none: + return IRQ_NONE; +} + +static struct irq_chip rtl8365mb_irq_chip =3D { + .name =3D "rtl8365mb", + /* The hardware doesn't support masking IRQs on a per-port basis */ +}; + +static int rtl8365mb_irq_map(struct irq_domain *domain, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_set_chip_data(irq, domain->host_data); + irq_set_chip_and_handler(irq, &rtl8365mb_irq_chip, handle_simple_irq); + irq_set_nested_thread(irq, 1); + irq_set_noprobe(irq); + + return 0; +} + +static void rtl8365mb_irq_unmap(struct irq_domain *d, unsigned int irq) +{ + irq_set_nested_thread(irq, 0); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); +} + +static const struct irq_domain_ops rtl8365mb_irqdomain_ops =3D { + .map =3D rtl8365mb_irq_map, + .unmap =3D rtl8365mb_irq_unmap, + .xlate =3D irq_domain_xlate_onecell, +}; + +static int rtl8365mb_set_irq_enable(struct realtek_smi *smi, bool enable) +{ + return regmap_update_bits(smi->map, RTL8365MB_INTR_CTRL_REG, + RTL8365MB_INTR_LINK_CHANGE_MASK, + FIELD_PREP(RTL8365MB_INTR_LINK_CHANGE_MASK, + enable ? 1 : 0)); +} + +static int rtl8365mb_irq_enable(struct realtek_smi *smi) +{ + return rtl8365mb_set_irq_enable(smi, true); +} + +static int rtl8365mb_irq_disable(struct realtek_smi *smi) +{ + return rtl8365mb_set_irq_enable(smi, false); +} + +static int rtl8365mb_irq_setup(struct realtek_smi *smi) +{ + struct rtl8365mb *mb =3D smi->chip_data; + struct device_node *intc; + u32 irq_trig; + int virq; + int irq; + u32 val; + int ret; + int i; + + intc =3D of_get_child_by_name(smi->dev->of_node, "interrupt-controller"); + if (!intc) { + dev_err(smi->dev, "missing child interrupt-controller node\n"); + return -EINVAL; + } + + /* rtl8365mb IRQs cascade off this one */ + irq =3D of_irq_get(intc, 0); + if (irq <=3D 0) { + if (irq !=3D -EPROBE_DEFER) + dev_err(smi->dev, "failed to get parent irq: %d\n", + irq); + ret =3D irq ? irq : -EINVAL; + goto out_put_node; + } + + smi->irqdomain =3D irq_domain_add_linear(intc, smi->num_ports, + &rtl8365mb_irqdomain_ops, smi); + if (!smi->irqdomain) { + dev_err(smi->dev, "failed to add irq domain\n"); + ret =3D -ENOMEM; + goto out_put_node; + } + + for (i =3D 0; i < smi->num_ports; i++) { + virq =3D irq_create_mapping(smi->irqdomain, i); + if (!virq) { + dev_err(smi->dev, + "failed to create irq domain mapping\n"); + ret =3D -EINVAL; + goto out_remove_irqdomain; + } + + irq_set_parent(virq, irq); + } + + /* Configure chip interrupt signal polarity */ + irq_trig =3D irqd_get_trigger_type(irq_get_irq_data(irq)); + switch (irq_trig) { + case IRQF_TRIGGER_RISING: + case IRQF_TRIGGER_HIGH: + val =3D RTL8365MB_INTR_POLARITY_HIGH; + break; + case IRQF_TRIGGER_FALLING: + case IRQF_TRIGGER_LOW: + val =3D RTL8365MB_INTR_POLARITY_LOW; + break; + default: + dev_err(smi->dev, "unsupported irq trigger type %u\n", + irq_trig); + ret =3D -EINVAL; + goto out_remove_irqdomain; + } + + ret =3D regmap_update_bits(smi->map, RTL8365MB_INTR_POLARITY_REG, + RTL8365MB_INTR_POLARITY_MASK, + FIELD_PREP(RTL8365MB_INTR_POLARITY_MASK, val)); + if (ret) + goto out_remove_irqdomain; + + /* Disable the interrupt in case the chip has it enabled on reset */ + ret =3D rtl8365mb_irq_disable(smi); + if (ret) + goto out_remove_irqdomain; + + /* Clear the interrupt status register */ + ret =3D regmap_write(smi->map, RTL8365MB_INTR_STATUS_REG, + RTL8365MB_INTR_ALL_MASK); + if (ret) + goto out_remove_irqdomain; + + ret =3D request_threaded_irq(irq, NULL, rtl8365mb_irq, IRQF_ONESHOT, + "rtl8365mb", smi); + if (ret) { + dev_err(smi->dev, "failed to request irq: %d\n", ret); + goto out_remove_irqdomain; + } + + /* Store the irq so that we know to free it during teardown */ + mb->irq =3D irq; + + ret =3D rtl8365mb_irq_enable(smi); + if (ret) + goto out_free_irq; + + of_node_put(intc); + + return 0; + +out_free_irq: + free_irq(mb->irq, smi); + mb->irq =3D 0; + +out_remove_irqdomain: + for (i =3D 0; i < smi->num_ports; i++) { + virq =3D irq_find_mapping(smi->irqdomain, i); + irq_dispose_mapping(virq); + } + + irq_domain_remove(smi->irqdomain); + smi->irqdomain =3D NULL; + +out_put_node: + of_node_put(intc); + + return ret; +} + +static void rtl8365mb_irq_teardown(struct realtek_smi *smi) +{ + struct rtl8365mb *mb =3D smi->chip_data; + int virq; + int i; + + if (mb->irq) { + free_irq(mb->irq, smi); + mb->irq =3D 0; + } + + if (smi->irqdomain) { + for (i =3D 0; i < smi->num_ports; i++) { + virq =3D irq_find_mapping(smi->irqdomain, i); + irq_dispose_mapping(virq); + } + + irq_domain_remove(smi->irqdomain); + smi->irqdomain =3D NULL; + } +} + +static int rtl8365mb_cpu_config(struct realtek_smi *smi) +{ + struct rtl8365mb *mb =3D smi->chip_data; + struct rtl8365mb_cpu *cpu =3D &mb->cpu; + u32 val; + int ret; + + ret =3D regmap_update_bits(smi->map, RTL8365MB_CPU_PORT_MASK_REG, + RTL8365MB_CPU_PORT_MASK_MASK, + FIELD_PREP(RTL8365MB_CPU_PORT_MASK_MASK, + cpu->mask)); + if (ret) + return ret; + + val =3D FIELD_PREP(RTL8365MB_CPU_CTRL_EN_MASK, cpu->enable ? 1 : 0) | + FIELD_PREP(RTL8365MB_CPU_CTRL_INSERTMODE_MASK, cpu->insert) | + FIELD_PREP(RTL8365MB_CPU_CTRL_TAG_POSITION_MASK, cpu->position) | + FIELD_PREP(RTL8365MB_CPU_CTRL_RXBYTECOUNT_MASK, cpu->rx_length) | + FIELD_PREP(RTL8365MB_CPU_CTRL_TAG_FORMAT_MASK, cpu->format) | + FIELD_PREP(RTL8365MB_CPU_CTRL_TRAP_PORT_MASK, cpu->trap_port) | + FIELD_PREP(RTL8365MB_CPU_CTRL_TRAP_PORT_EXT_MASK, + cpu->trap_port >> 3); + ret =3D regmap_write(smi->map, RTL8365MB_CPU_CTRL_REG, val); + if (ret) + return ret; + + return 0; +} + +static int rtl8365mb_switch_init(struct realtek_smi *smi) +{ + struct rtl8365mb *mb =3D smi->chip_data; + int ret; + int i; + + /* Do any chip-specific init jam before getting to the common stuff */ + if (mb->jam_table) { + for (i =3D 0; i < mb->jam_size; i++) { + ret =3D regmap_write(smi->map, mb->jam_table[i].reg, + mb->jam_table[i].val); + if (ret) + return ret; + } + } + + /* Common init jam */ + for (i =3D 0; i < ARRAY_SIZE(rtl8365mb_init_jam_common); i++) { + ret =3D regmap_write(smi->map, rtl8365mb_init_jam_common[i].reg, + rtl8365mb_init_jam_common[i].val); + if (ret) + return ret; + } + + return 0; +} + +static int rtl8365mb_reset_chip(struct realtek_smi *smi) +{ + u32 val; + + realtek_smi_write_reg_noack(smi, RTL8365MB_CHIP_RESET_REG, + FIELD_PREP(RTL8365MB_CHIP_RESET_HW_MASK, + 1)); + + /* Realtek documentation says the chip needs 1 second to reset. Sleep + * for 100 ms before accessing any registers to prevent ACK timeouts. + */ + msleep(100); + return regmap_read_poll_timeout(smi->map, RTL8365MB_CHIP_RESET_REG, val, + !(val & RTL8365MB_CHIP_RESET_HW_MASK), + 20000, 1e6); +} + +static int rtl8365mb_setup(struct dsa_switch *ds) +{ + struct realtek_smi *smi =3D ds->priv; + struct rtl8365mb *mb; + int ret; + int i; + + mb =3D smi->chip_data; + + ret =3D rtl8365mb_reset_chip(smi); + if (ret) { + dev_err(smi->dev, "failed to reset chip: %d\n", ret); + goto out_error; + } + + /* Configure switch to vendor-defined initial state */ + ret =3D rtl8365mb_switch_init(smi); + if (ret) { + dev_err(smi->dev, "failed to initialize switch: %d\n", ret); + goto out_error; + } + + /* Set up cascading IRQs */ + ret =3D rtl8365mb_irq_setup(smi); + if (ret =3D=3D -EPROBE_DEFER) + return ret; + else if (ret) + dev_info(smi->dev, "no interrupt support\n"); + + /* Configure CPU tagging */ + ret =3D rtl8365mb_cpu_config(smi); + if (ret) + goto out_teardown_irq; + + /* Configure ports */ + for (i =3D 0; i < smi->num_ports; i++) { + struct rtl8365mb_port *p =3D &mb->ports[i]; + + if (dsa_is_unused_port(smi->ds, i)) + continue; + + /* Set up per-port private data */ + p->smi =3D smi; + p->index =3D i; + + /* Forward only to the CPU */ + ret =3D rtl8365mb_port_set_isolation(smi, i, BIT(smi->cpu_port)); + if (ret) + goto out_teardown_irq; + + /* Disable learning */ + ret =3D rtl8365mb_port_set_learning(smi, i, false); + if (ret) + goto out_teardown_irq; + + /* Set the initial STP state of all ports to DISABLED, otherwise + * ports will still forward frames to the CPU despite being + * administratively down by default. + */ + rtl8365mb_port_stp_state_set(smi->ds, i, BR_STATE_DISABLED); + } + + /* Set maximum packet length to 1536 bytes */ + ret =3D regmap_update_bits(smi->map, RTL8365MB_CFG0_MAX_LEN_REG, + RTL8365MB_CFG0_MAX_LEN_MASK, + FIELD_PREP(RTL8365MB_CFG0_MAX_LEN_MASK, 1536)); + if (ret) + goto out_teardown_irq; + + ret =3D realtek_smi_setup_mdio(smi); + if (ret) { + dev_err(smi->dev, "could not set up MDIO bus\n"); + goto out_teardown_irq; + } + + /* Start statistics counter polling */ + rtl8365mb_stats_setup(smi); + + return 0; + +out_teardown_irq: + rtl8365mb_irq_teardown(smi); + +out_error: + return ret; +} + +static void rtl8365mb_teardown(struct dsa_switch *ds) +{ + struct realtek_smi *smi =3D ds->priv; + + rtl8365mb_stats_teardown(smi); + rtl8365mb_irq_teardown(smi); +} + +static int rtl8365mb_get_chip_id_and_ver(struct regmap *map, u32 *id, u32 = *ver) +{ + int ret; + + /* For some reason we have to write a magic value to an arbitrary + * register whenever accessing the chip ID/version registers. + */ + ret =3D regmap_write(map, RTL8365MB_MAGIC_REG, RTL8365MB_MAGIC_VALUE); + if (ret) + return ret; + + ret =3D regmap_read(map, RTL8365MB_CHIP_ID_REG, id); + if (ret) + return ret; + + ret =3D regmap_read(map, RTL8365MB_CHIP_VER_REG, ver); + if (ret) + return ret; + + /* Reset magic register */ + ret =3D regmap_write(map, RTL8365MB_MAGIC_REG, 0); + if (ret) + return ret; + + return 0; +} + +static int rtl8365mb_detect(struct realtek_smi *smi) +{ + struct rtl8365mb *mb =3D smi->chip_data; + u32 chip_id; + u32 chip_ver; + int ret; + + ret =3D rtl8365mb_get_chip_id_and_ver(smi->map, &chip_id, &chip_ver); + if (ret) { + dev_err(smi->dev, "failed to read chip id and version: %d\n", + ret); + return ret; + } + + switch (chip_id) { + case RTL8365MB_CHIP_ID_8365MB_VC: + dev_info(smi->dev, + "found an RTL8365MB-VC switch (ver=3D0x%04x)\n", + chip_ver); + + smi->cpu_port =3D RTL8365MB_CPU_PORT_NUM_8365MB_VC; + smi->num_ports =3D smi->cpu_port + 1; + + mb->smi =3D smi; + mb->chip_id =3D chip_id; + mb->chip_ver =3D chip_ver; + mb->port_mask =3D BIT(smi->num_ports) - 1; + mb->learn_limit_max =3D RTL8365MB_LEARN_LIMIT_MAX_8365MB_VC; + mb->jam_table =3D rtl8365mb_init_jam_8365mb_vc; + mb->jam_size =3D ARRAY_SIZE(rtl8365mb_init_jam_8365mb_vc); + + mb->cpu.enable =3D 1; + mb->cpu.mask =3D BIT(smi->cpu_port); + mb->cpu.trap_port =3D smi->cpu_port; + mb->cpu.insert =3D RTL8365MB_CPU_INSERT_TO_ALL; + mb->cpu.position =3D RTL8365MB_CPU_POS_AFTER_SA; + mb->cpu.rx_length =3D RTL8365MB_CPU_RXLEN_64BYTES; + mb->cpu.format =3D RTL8365MB_CPU_FORMAT_8BYTES; + + break; + default: + dev_err(smi->dev, + "found an unknown Realtek switch (id=3D0x%04x, ver=3D0x%04x)\n", + chip_id, chip_ver); + return -ENODEV; + } + + return 0; +} + +static const struct dsa_switch_ops rtl8365mb_switch_ops =3D { + .get_tag_protocol =3D rtl8365mb_get_tag_protocol, + .setup =3D rtl8365mb_setup, + .teardown =3D rtl8365mb_teardown, + .phylink_validate =3D rtl8365mb_phylink_validate, + .phylink_mac_config =3D rtl8365mb_phylink_mac_config, + .phylink_mac_link_down =3D rtl8365mb_phylink_mac_link_down, + .phylink_mac_link_up =3D rtl8365mb_phylink_mac_link_up, + .port_stp_state_set =3D rtl8365mb_port_stp_state_set, + .get_strings =3D rtl8365mb_get_strings, + .get_ethtool_stats =3D rtl8365mb_get_ethtool_stats, + .get_sset_count =3D rtl8365mb_get_sset_count, + .get_eth_phy_stats =3D rtl8365mb_get_phy_stats, + .get_eth_mac_stats =3D rtl8365mb_get_mac_stats, + .get_eth_ctrl_stats =3D rtl8365mb_get_ctrl_stats, + .get_stats64 =3D rtl8365mb_get_stats64, +}; + +static const struct realtek_smi_ops rtl8365mb_smi_ops =3D { + .detect =3D rtl8365mb_detect, + .phy_read =3D rtl8365mb_phy_read, + .phy_write =3D rtl8365mb_phy_write, +}; + +const struct realtek_smi_variant rtl8365mb_variant =3D { + .ds_ops =3D &rtl8365mb_switch_ops, + .ops =3D &rtl8365mb_smi_ops, + .clk_delay =3D 10, + .cmd_read =3D 0xb9, + .cmd_write =3D 0xb8, + .chip_data_sz =3D sizeof(struct rtl8365mb), +}; +EXPORT_SYMBOL_GPL(rtl8365mb_variant); diff --git a/drivers/net/dsa/realtek/rtl8366.c b/drivers/net/dsa/realtek/rt= l8366.c new file mode 100644 index 000000000000..bdb8d8d34880 --- /dev/null +++ b/drivers/net/dsa/realtek/rtl8366.c @@ -0,0 +1,448 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Realtek SMI library helpers for the RTL8366x variants + * RTL8366RB and RTL8366S + * + * Copyright (C) 2017 Linus Walleij + * Copyright (C) 2009-2010 Gabor Juhos + * Copyright (C) 2010 Antti Sepp=C3=A4l=C3=A4 + * Copyright (C) 2010 Roman Yeryomin + * Copyright (C) 2011 Colin Leitner + */ +#include +#include + +#include "realtek-smi-core.h" + +int rtl8366_mc_is_used(struct realtek_smi *smi, int mc_index, int *used) +{ + int ret; + int i; + + *used =3D 0; + for (i =3D 0; i < smi->num_ports; i++) { + int index =3D 0; + + ret =3D smi->ops->get_mc_index(smi, i, &index); + if (ret) + return ret; + + if (mc_index =3D=3D index) { + *used =3D 1; + break; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_mc_is_used); + +/** + * rtl8366_obtain_mc() - retrieve or allocate a VLAN member configuration + * @smi: the Realtek SMI device instance + * @vid: the VLAN ID to look up or allocate + * @vlanmc: the pointer will be assigned to a pointer to a valid member co= nfig + * if successful + * @return: index of a new member config or negative error number + */ +static int rtl8366_obtain_mc(struct realtek_smi *smi, int vid, + struct rtl8366_vlan_mc *vlanmc) +{ + struct rtl8366_vlan_4k vlan4k; + int ret; + int i; + + /* Try to find an existing member config entry for this VID */ + for (i =3D 0; i < smi->num_vlan_mc; i++) { + ret =3D smi->ops->get_vlan_mc(smi, i, vlanmc); + if (ret) { + dev_err(smi->dev, "error searching for VLAN MC %d for VID %d\n", + i, vid); + return ret; + } + + if (vid =3D=3D vlanmc->vid) + return i; + } + + /* We have no MC entry for this VID, try to find an empty one */ + for (i =3D 0; i < smi->num_vlan_mc; i++) { + ret =3D smi->ops->get_vlan_mc(smi, i, vlanmc); + if (ret) { + dev_err(smi->dev, "error searching for VLAN MC %d for VID %d\n", + i, vid); + return ret; + } + + if (vlanmc->vid =3D=3D 0 && vlanmc->member =3D=3D 0) { + /* Update the entry from the 4K table */ + ret =3D smi->ops->get_vlan_4k(smi, vid, &vlan4k); + if (ret) { + dev_err(smi->dev, "error looking for 4K VLAN MC %d for VID %d\n", + i, vid); + return ret; + } + + vlanmc->vid =3D vid; + vlanmc->member =3D vlan4k.member; + vlanmc->untag =3D vlan4k.untag; + vlanmc->fid =3D vlan4k.fid; + ret =3D smi->ops->set_vlan_mc(smi, i, vlanmc); + if (ret) { + dev_err(smi->dev, "unable to set/update VLAN MC %d for VID %d\n", + i, vid); + return ret; + } + + dev_dbg(smi->dev, "created new MC at index %d for VID %d\n", + i, vid); + return i; + } + } + + /* MC table is full, try to find an unused entry and replace it */ + for (i =3D 0; i < smi->num_vlan_mc; i++) { + int used; + + ret =3D rtl8366_mc_is_used(smi, i, &used); + if (ret) + return ret; + + if (!used) { + /* Update the entry from the 4K table */ + ret =3D smi->ops->get_vlan_4k(smi, vid, &vlan4k); + if (ret) + return ret; + + vlanmc->vid =3D vid; + vlanmc->member =3D vlan4k.member; + vlanmc->untag =3D vlan4k.untag; + vlanmc->fid =3D vlan4k.fid; + ret =3D smi->ops->set_vlan_mc(smi, i, vlanmc); + if (ret) { + dev_err(smi->dev, "unable to set/update VLAN MC %d for VID %d\n", + i, vid); + return ret; + } + dev_dbg(smi->dev, "recycled MC at index %i for VID %d\n", + i, vid); + return i; + } + } + + dev_err(smi->dev, "all VLAN member configurations are in use\n"); + return -ENOSPC; +} + +int rtl8366_set_vlan(struct realtek_smi *smi, int vid, u32 member, + u32 untag, u32 fid) +{ + struct rtl8366_vlan_mc vlanmc; + struct rtl8366_vlan_4k vlan4k; + int mc; + int ret; + + if (!smi->ops->is_vlan_valid(smi, vid)) + return -EINVAL; + + dev_dbg(smi->dev, + "setting VLAN%d 4k members: 0x%02x, untagged: 0x%02x\n", + vid, member, untag); + + /* Update the 4K table */ + ret =3D smi->ops->get_vlan_4k(smi, vid, &vlan4k); + if (ret) + return ret; + + vlan4k.member |=3D member; + vlan4k.untag |=3D untag; + vlan4k.fid =3D fid; + ret =3D smi->ops->set_vlan_4k(smi, &vlan4k); + if (ret) + return ret; + + dev_dbg(smi->dev, + "resulting VLAN%d 4k members: 0x%02x, untagged: 0x%02x\n", + vid, vlan4k.member, vlan4k.untag); + + /* Find or allocate a member config for this VID */ + ret =3D rtl8366_obtain_mc(smi, vid, &vlanmc); + if (ret < 0) + return ret; + mc =3D ret; + + /* Update the MC entry */ + vlanmc.member |=3D member; + vlanmc.untag |=3D untag; + vlanmc.fid =3D fid; + + /* Commit updates to the MC entry */ + ret =3D smi->ops->set_vlan_mc(smi, mc, &vlanmc); + if (ret) + dev_err(smi->dev, "failed to commit changes to VLAN MC index %d for VID = %d\n", + mc, vid); + else + dev_dbg(smi->dev, + "resulting VLAN%d MC members: 0x%02x, untagged: 0x%02x\n", + vid, vlanmc.member, vlanmc.untag); + + return ret; +} +EXPORT_SYMBOL_GPL(rtl8366_set_vlan); + +int rtl8366_set_pvid(struct realtek_smi *smi, unsigned int port, + unsigned int vid) +{ + struct rtl8366_vlan_mc vlanmc; + int mc; + int ret; + + if (!smi->ops->is_vlan_valid(smi, vid)) + return -EINVAL; + + /* Find or allocate a member config for this VID */ + ret =3D rtl8366_obtain_mc(smi, vid, &vlanmc); + if (ret < 0) + return ret; + mc =3D ret; + + ret =3D smi->ops->set_mc_index(smi, port, mc); + if (ret) { + dev_err(smi->dev, "set PVID: failed to set MC index %d for port %d\n", + mc, port); + return ret; + } + + dev_dbg(smi->dev, "set PVID: the PVID for port %d set to %d using existin= g MC index %d\n", + port, vid, mc); + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_set_pvid); + +int rtl8366_enable_vlan4k(struct realtek_smi *smi, bool enable) +{ + int ret; + + /* To enable 4k VLAN, ordinary VLAN must be enabled first, + * but if we disable 4k VLAN it is fine to leave ordinary + * VLAN enabled. + */ + if (enable) { + /* Make sure VLAN is ON */ + ret =3D smi->ops->enable_vlan(smi, true); + if (ret) + return ret; + + smi->vlan_enabled =3D true; + } + + ret =3D smi->ops->enable_vlan4k(smi, enable); + if (ret) + return ret; + + smi->vlan4k_enabled =3D enable; + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_enable_vlan4k); + +int rtl8366_enable_vlan(struct realtek_smi *smi, bool enable) +{ + int ret; + + ret =3D smi->ops->enable_vlan(smi, enable); + if (ret) + return ret; + + smi->vlan_enabled =3D enable; + + /* If we turn VLAN off, make sure that we turn off + * 4k VLAN as well, if that happened to be on. + */ + if (!enable) { + smi->vlan4k_enabled =3D false; + ret =3D smi->ops->enable_vlan4k(smi, false); + } + + return ret; +} +EXPORT_SYMBOL_GPL(rtl8366_enable_vlan); + +int rtl8366_reset_vlan(struct realtek_smi *smi) +{ + struct rtl8366_vlan_mc vlanmc; + int ret; + int i; + + rtl8366_enable_vlan(smi, false); + rtl8366_enable_vlan4k(smi, false); + + /* Clear the 16 VLAN member configurations */ + vlanmc.vid =3D 0; + vlanmc.priority =3D 0; + vlanmc.member =3D 0; + vlanmc.untag =3D 0; + vlanmc.fid =3D 0; + for (i =3D 0; i < smi->num_vlan_mc; i++) { + ret =3D smi->ops->set_vlan_mc(smi, i, &vlanmc); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_reset_vlan); + +int rtl8366_vlan_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan, + struct netlink_ext_ack *extack) +{ + bool untagged =3D !!(vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED); + bool pvid =3D !!(vlan->flags & BRIDGE_VLAN_INFO_PVID); + struct realtek_smi *smi =3D ds->priv; + u32 member =3D 0; + u32 untag =3D 0; + int ret; + + if (!smi->ops->is_vlan_valid(smi, vlan->vid)) { + NL_SET_ERR_MSG_MOD(extack, "VLAN ID not valid"); + return -EINVAL; + } + + /* Enable VLAN in the hardware + * FIXME: what's with this 4k business? + * Just rtl8366_enable_vlan() seems inconclusive. + */ + ret =3D rtl8366_enable_vlan4k(smi, true); + if (ret) { + NL_SET_ERR_MSG_MOD(extack, "Failed to enable VLAN 4K"); + return ret; + } + + dev_dbg(smi->dev, "add VLAN %d on port %d, %s, %s\n", + vlan->vid, port, untagged ? "untagged" : "tagged", + pvid ? "PVID" : "no PVID"); + + member |=3D BIT(port); + + if (untagged) + untag |=3D BIT(port); + + ret =3D rtl8366_set_vlan(smi, vlan->vid, member, untag, 0); + if (ret) { + dev_err(smi->dev, "failed to set up VLAN %04x", vlan->vid); + return ret; + } + + if (!pvid) + return 0; + + ret =3D rtl8366_set_pvid(smi, port, vlan->vid); + if (ret) { + dev_err(smi->dev, "failed to set PVID on port %d to VLAN %04x", + port, vlan->vid); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_vlan_add); + +int rtl8366_vlan_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan) +{ + struct realtek_smi *smi =3D ds->priv; + int ret, i; + + dev_dbg(smi->dev, "del VLAN %d on port %d\n", vlan->vid, port); + + for (i =3D 0; i < smi->num_vlan_mc; i++) { + struct rtl8366_vlan_mc vlanmc; + + ret =3D smi->ops->get_vlan_mc(smi, i, &vlanmc); + if (ret) + return ret; + + if (vlan->vid =3D=3D vlanmc.vid) { + /* Remove this port from the VLAN */ + vlanmc.member &=3D ~BIT(port); + vlanmc.untag &=3D ~BIT(port); + /* + * If no ports are members of this VLAN + * anymore then clear the whole member + * config so it can be reused. + */ + if (!vlanmc.member) { + vlanmc.vid =3D 0; + vlanmc.priority =3D 0; + vlanmc.fid =3D 0; + } + ret =3D smi->ops->set_vlan_mc(smi, i, &vlanmc); + if (ret) { + dev_err(smi->dev, + "failed to remove VLAN %04x\n", + vlan->vid); + return ret; + } + break; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_vlan_del); + +void rtl8366_get_strings(struct dsa_switch *ds, int port, u32 stringset, + uint8_t *data) +{ + struct realtek_smi *smi =3D ds->priv; + struct rtl8366_mib_counter *mib; + int i; + + if (port >=3D smi->num_ports) + return; + + for (i =3D 0; i < smi->num_mib_counters; i++) { + mib =3D &smi->mib_counters[i]; + strncpy(data + i * ETH_GSTRING_LEN, + mib->name, ETH_GSTRING_LEN); + } +} +EXPORT_SYMBOL_GPL(rtl8366_get_strings); + +int rtl8366_get_sset_count(struct dsa_switch *ds, int port, int sset) +{ + struct realtek_smi *smi =3D ds->priv; + + /* We only support SS_STATS */ + if (sset !=3D ETH_SS_STATS) + return 0; + if (port >=3D smi->num_ports) + return -EINVAL; + + return smi->num_mib_counters; +} +EXPORT_SYMBOL_GPL(rtl8366_get_sset_count); + +void rtl8366_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *= data) +{ + struct realtek_smi *smi =3D ds->priv; + int i; + int ret; + + if (port >=3D smi->num_ports) + return; + + for (i =3D 0; i < smi->num_mib_counters; i++) { + struct rtl8366_mib_counter *mib; + u64 mibvalue =3D 0; + + mib =3D &smi->mib_counters[i]; + ret =3D smi->ops->get_mib_counter(smi, port, mib, &mibvalue); + if (ret) { + dev_err(smi->dev, "error reading MIB counter %s\n", + mib->name); + } + data[i] =3D mibvalue; + } +} +EXPORT_SYMBOL_GPL(rtl8366_get_ethtool_stats); diff --git a/drivers/net/dsa/realtek/rtl8366rb.c b/drivers/net/dsa/realtek/= rtl8366rb.c new file mode 100644 index 000000000000..2a523a33529b --- /dev/null +++ b/drivers/net/dsa/realtek/rtl8366rb.c @@ -0,0 +1,1815 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Realtek SMI subdriver for the Realtek RTL8366RB ethernet switch + * + * This is a sparsely documented chip, the only viable documentation seems + * to be a patched up code drop from the vendor that appear in various + * GPL source trees. + * + * Copyright (C) 2017 Linus Walleij + * Copyright (C) 2009-2010 Gabor Juhos + * Copyright (C) 2010 Antti Sepp=C3=A4l=C3=A4 + * Copyright (C) 2010 Roman Yeryomin + * Copyright (C) 2011 Colin Leitner + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "realtek-smi-core.h" + +#define RTL8366RB_PORT_NUM_CPU 5 +#define RTL8366RB_NUM_PORTS 6 +#define RTL8366RB_PHY_NO_MAX 4 +#define RTL8366RB_PHY_ADDR_MAX 31 + +/* Switch Global Configuration register */ +#define RTL8366RB_SGCR 0x0000 +#define RTL8366RB_SGCR_EN_BC_STORM_CTRL BIT(0) +#define RTL8366RB_SGCR_MAX_LENGTH(a) ((a) << 4) +#define RTL8366RB_SGCR_MAX_LENGTH_MASK RTL8366RB_SGCR_MAX_LENGTH(0x3) +#define RTL8366RB_SGCR_MAX_LENGTH_1522 RTL8366RB_SGCR_MAX_LENGTH(0x0) +#define RTL8366RB_SGCR_MAX_LENGTH_1536 RTL8366RB_SGCR_MAX_LENGTH(0x1) +#define RTL8366RB_SGCR_MAX_LENGTH_1552 RTL8366RB_SGCR_MAX_LENGTH(0x2) +#define RTL8366RB_SGCR_MAX_LENGTH_16000 RTL8366RB_SGCR_MAX_LENGTH(0x3) +#define RTL8366RB_SGCR_EN_VLAN BIT(13) +#define RTL8366RB_SGCR_EN_VLAN_4KTB BIT(14) + +/* Port Enable Control register */ +#define RTL8366RB_PECR 0x0001 + +/* Switch per-port learning disablement register */ +#define RTL8366RB_PORT_LEARNDIS_CTRL 0x0002 + +/* Security control, actually aging register */ +#define RTL8366RB_SECURITY_CTRL 0x0003 + +#define RTL8366RB_SSCR2 0x0004 +#define RTL8366RB_SSCR2_DROP_UNKNOWN_DA BIT(0) + +/* Port Mode Control registers */ +#define RTL8366RB_PMC0 0x0005 +#define RTL8366RB_PMC0_SPI BIT(0) +#define RTL8366RB_PMC0_EN_AUTOLOAD BIT(1) +#define RTL8366RB_PMC0_PROBE BIT(2) +#define RTL8366RB_PMC0_DIS_BISR BIT(3) +#define RTL8366RB_PMC0_ADCTEST BIT(4) +#define RTL8366RB_PMC0_SRAM_DIAG BIT(5) +#define RTL8366RB_PMC0_EN_SCAN BIT(6) +#define RTL8366RB_PMC0_P4_IOMODE_SHIFT 7 +#define RTL8366RB_PMC0_P4_IOMODE_MASK GENMASK(9, 7) +#define RTL8366RB_PMC0_P5_IOMODE_SHIFT 10 +#define RTL8366RB_PMC0_P5_IOMODE_MASK GENMASK(12, 10) +#define RTL8366RB_PMC0_SDSMODE_SHIFT 13 +#define RTL8366RB_PMC0_SDSMODE_MASK GENMASK(15, 13) +#define RTL8366RB_PMC1 0x0006 + +/* Port Mirror Control Register */ +#define RTL8366RB_PMCR 0x0007 +#define RTL8366RB_PMCR_SOURCE_PORT(a) (a) +#define RTL8366RB_PMCR_SOURCE_PORT_MASK 0x000f +#define RTL8366RB_PMCR_MONITOR_PORT(a) ((a) << 4) +#define RTL8366RB_PMCR_MONITOR_PORT_MASK 0x00f0 +#define RTL8366RB_PMCR_MIRROR_RX BIT(8) +#define RTL8366RB_PMCR_MIRROR_TX BIT(9) +#define RTL8366RB_PMCR_MIRROR_SPC BIT(10) +#define RTL8366RB_PMCR_MIRROR_ISO BIT(11) + +/* bits 0..7 =3D port 0, bits 8..15 =3D port 1 */ +#define RTL8366RB_PAACR0 0x0010 +/* bits 0..7 =3D port 2, bits 8..15 =3D port 3 */ +#define RTL8366RB_PAACR1 0x0011 +/* bits 0..7 =3D port 4, bits 8..15 =3D port 5 */ +#define RTL8366RB_PAACR2 0x0012 +#define RTL8366RB_PAACR_SPEED_10M 0 +#define RTL8366RB_PAACR_SPEED_100M 1 +#define RTL8366RB_PAACR_SPEED_1000M 2 +#define RTL8366RB_PAACR_FULL_DUPLEX BIT(2) +#define RTL8366RB_PAACR_LINK_UP BIT(4) +#define RTL8366RB_PAACR_TX_PAUSE BIT(5) +#define RTL8366RB_PAACR_RX_PAUSE BIT(6) +#define RTL8366RB_PAACR_AN BIT(7) + +#define RTL8366RB_PAACR_CPU_PORT (RTL8366RB_PAACR_SPEED_1000M | \ + RTL8366RB_PAACR_FULL_DUPLEX | \ + RTL8366RB_PAACR_LINK_UP | \ + RTL8366RB_PAACR_TX_PAUSE | \ + RTL8366RB_PAACR_RX_PAUSE) + +/* bits 0..7 =3D port 0, bits 8..15 =3D port 1 */ +#define RTL8366RB_PSTAT0 0x0014 +/* bits 0..7 =3D port 2, bits 8..15 =3D port 3 */ +#define RTL8366RB_PSTAT1 0x0015 +/* bits 0..7 =3D port 4, bits 8..15 =3D port 5 */ +#define RTL8366RB_PSTAT2 0x0016 + +#define RTL8366RB_POWER_SAVING_REG 0x0021 + +/* Spanning tree status (STP) control, two bits per port per FID */ +#define RTL8366RB_STP_STATE_BASE 0x0050 /* 0x0050..0x0057 */ +#define RTL8366RB_STP_STATE_DISABLED 0x0 +#define RTL8366RB_STP_STATE_BLOCKING 0x1 +#define RTL8366RB_STP_STATE_LEARNING 0x2 +#define RTL8366RB_STP_STATE_FORWARDING 0x3 +#define RTL8366RB_STP_MASK GENMASK(1, 0) +#define RTL8366RB_STP_STATE(port, state) \ + ((state) << ((port) * 2)) +#define RTL8366RB_STP_STATE_MASK(port) \ + RTL8366RB_STP_STATE((port), RTL8366RB_STP_MASK) + +/* CPU port control reg */ +#define RTL8368RB_CPU_CTRL_REG 0x0061 +#define RTL8368RB_CPU_PORTS_MSK 0x00FF +/* Disables inserting custom tag length/type 0x8899 */ +#define RTL8368RB_CPU_NO_TAG BIT(15) + +#define RTL8366RB_SMAR0 0x0070 /* bits 0..15 */ +#define RTL8366RB_SMAR1 0x0071 /* bits 16..31 */ +#define RTL8366RB_SMAR2 0x0072 /* bits 32..47 */ + +#define RTL8366RB_RESET_CTRL_REG 0x0100 +#define RTL8366RB_CHIP_CTRL_RESET_HW BIT(0) +#define RTL8366RB_CHIP_CTRL_RESET_SW BIT(1) + +#define RTL8366RB_CHIP_ID_REG 0x0509 +#define RTL8366RB_CHIP_ID_8366 0x5937 +#define RTL8366RB_CHIP_VERSION_CTRL_REG 0x050A +#define RTL8366RB_CHIP_VERSION_MASK 0xf + +/* PHY registers control */ +#define RTL8366RB_PHY_ACCESS_CTRL_REG 0x8000 +#define RTL8366RB_PHY_CTRL_READ BIT(0) +#define RTL8366RB_PHY_CTRL_WRITE 0 +#define RTL8366RB_PHY_ACCESS_BUSY_REG 0x8001 +#define RTL8366RB_PHY_INT_BUSY BIT(0) +#define RTL8366RB_PHY_EXT_BUSY BIT(4) +#define RTL8366RB_PHY_ACCESS_DATA_REG 0x8002 +#define RTL8366RB_PHY_EXT_CTRL_REG 0x8010 +#define RTL8366RB_PHY_EXT_WRDATA_REG 0x8011 +#define RTL8366RB_PHY_EXT_RDDATA_REG 0x8012 + +#define RTL8366RB_PHY_REG_MASK 0x1f +#define RTL8366RB_PHY_PAGE_OFFSET 5 +#define RTL8366RB_PHY_PAGE_MASK (0xf << 5) +#define RTL8366RB_PHY_NO_OFFSET 9 +#define RTL8366RB_PHY_NO_MASK (0x1f << 9) + +/* VLAN Ingress Control Register 1, one bit per port. + * bit 0 .. 5 will make the switch drop ingress frames without + * VID such as untagged or priority-tagged frames for respective + * port. + * bit 6 .. 11 will make the switch drop ingress frames carrying + * a C-tag with VID !=3D 0 for respective port. + */ +#define RTL8366RB_VLAN_INGRESS_CTRL1_REG 0x037E +#define RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port) (BIT((port)) | BIT((port) = + 6)) + +/* VLAN Ingress Control Register 2, one bit per port. + * bit0 .. bit5 will make the switch drop all ingress frames with + * a VLAN classification that does not include the port is in its + * member set. + */ +#define RTL8366RB_VLAN_INGRESS_CTRL2_REG 0x037f + +/* LED control registers */ +#define RTL8366RB_LED_BLINKRATE_REG 0x0430 +#define RTL8366RB_LED_BLINKRATE_MASK 0x0007 +#define RTL8366RB_LED_BLINKRATE_28MS 0x0000 +#define RTL8366RB_LED_BLINKRATE_56MS 0x0001 +#define RTL8366RB_LED_BLINKRATE_84MS 0x0002 +#define RTL8366RB_LED_BLINKRATE_111MS 0x0003 +#define RTL8366RB_LED_BLINKRATE_222MS 0x0004 +#define RTL8366RB_LED_BLINKRATE_446MS 0x0005 + +#define RTL8366RB_LED_CTRL_REG 0x0431 +#define RTL8366RB_LED_OFF 0x0 +#define RTL8366RB_LED_DUP_COL 0x1 +#define RTL8366RB_LED_LINK_ACT 0x2 +#define RTL8366RB_LED_SPD1000 0x3 +#define RTL8366RB_LED_SPD100 0x4 +#define RTL8366RB_LED_SPD10 0x5 +#define RTL8366RB_LED_SPD1000_ACT 0x6 +#define RTL8366RB_LED_SPD100_ACT 0x7 +#define RTL8366RB_LED_SPD10_ACT 0x8 +#define RTL8366RB_LED_SPD100_10_ACT 0x9 +#define RTL8366RB_LED_FIBER 0xa +#define RTL8366RB_LED_AN_FAULT 0xb +#define RTL8366RB_LED_LINK_RX 0xc +#define RTL8366RB_LED_LINK_TX 0xd +#define RTL8366RB_LED_MASTER 0xe +#define RTL8366RB_LED_FORCE 0xf +#define RTL8366RB_LED_0_1_CTRL_REG 0x0432 +#define RTL8366RB_LED_1_OFFSET 6 +#define RTL8366RB_LED_2_3_CTRL_REG 0x0433 +#define RTL8366RB_LED_3_OFFSET 6 + +#define RTL8366RB_MIB_COUNT 33 +#define RTL8366RB_GLOBAL_MIB_COUNT 1 +#define RTL8366RB_MIB_COUNTER_PORT_OFFSET 0x0050 +#define RTL8366RB_MIB_COUNTER_BASE 0x1000 +#define RTL8366RB_MIB_CTRL_REG 0x13F0 +#define RTL8366RB_MIB_CTRL_USER_MASK 0x0FFC +#define RTL8366RB_MIB_CTRL_BUSY_MASK BIT(0) +#define RTL8366RB_MIB_CTRL_RESET_MASK BIT(1) +#define RTL8366RB_MIB_CTRL_PORT_RESET(_p) BIT(2 + (_p)) +#define RTL8366RB_MIB_CTRL_GLOBAL_RESET BIT(11) + +#define RTL8366RB_PORT_VLAN_CTRL_BASE 0x0063 +#define RTL8366RB_PORT_VLAN_CTRL_REG(_p) \ + (RTL8366RB_PORT_VLAN_CTRL_BASE + (_p) / 4) +#define RTL8366RB_PORT_VLAN_CTRL_MASK 0xf +#define RTL8366RB_PORT_VLAN_CTRL_SHIFT(_p) (4 * ((_p) % 4)) + +#define RTL8366RB_VLAN_TABLE_READ_BASE 0x018C +#define RTL8366RB_VLAN_TABLE_WRITE_BASE 0x0185 + +#define RTL8366RB_TABLE_ACCESS_CTRL_REG 0x0180 +#define RTL8366RB_TABLE_VLAN_READ_CTRL 0x0E01 +#define RTL8366RB_TABLE_VLAN_WRITE_CTRL 0x0F01 + +#define RTL8366RB_VLAN_MC_BASE(_x) (0x0020 + (_x) * 3) + +#define RTL8366RB_PORT_LINK_STATUS_BASE 0x0014 +#define RTL8366RB_PORT_STATUS_SPEED_MASK 0x0003 +#define RTL8366RB_PORT_STATUS_DUPLEX_MASK 0x0004 +#define RTL8366RB_PORT_STATUS_LINK_MASK 0x0010 +#define RTL8366RB_PORT_STATUS_TXPAUSE_MASK 0x0020 +#define RTL8366RB_PORT_STATUS_RXPAUSE_MASK 0x0040 +#define RTL8366RB_PORT_STATUS_AN_MASK 0x0080 + +#define RTL8366RB_NUM_VLANS 16 +#define RTL8366RB_NUM_LEDGROUPS 4 +#define RTL8366RB_NUM_VIDS 4096 +#define RTL8366RB_PRIORITYMAX 7 +#define RTL8366RB_NUM_FIDS 8 +#define RTL8366RB_FIDMAX 7 + +#define RTL8366RB_PORT_1 BIT(0) /* In userspace port 0 */ +#define RTL8366RB_PORT_2 BIT(1) /* In userspace port 1 */ +#define RTL8366RB_PORT_3 BIT(2) /* In userspace port 2 */ +#define RTL8366RB_PORT_4 BIT(3) /* In userspace port 3 */ +#define RTL8366RB_PORT_5 BIT(4) /* In userspace port 4 */ + +#define RTL8366RB_PORT_CPU BIT(5) /* CPU port */ + +#define RTL8366RB_PORT_ALL (RTL8366RB_PORT_1 | \ + RTL8366RB_PORT_2 | \ + RTL8366RB_PORT_3 | \ + RTL8366RB_PORT_4 | \ + RTL8366RB_PORT_5 | \ + RTL8366RB_PORT_CPU) + +#define RTL8366RB_PORT_ALL_BUT_CPU (RTL8366RB_PORT_1 | \ + RTL8366RB_PORT_2 | \ + RTL8366RB_PORT_3 | \ + RTL8366RB_PORT_4 | \ + RTL8366RB_PORT_5) + +#define RTL8366RB_PORT_ALL_EXTERNAL (RTL8366RB_PORT_1 | \ + RTL8366RB_PORT_2 | \ + RTL8366RB_PORT_3 | \ + RTL8366RB_PORT_4) + +#define RTL8366RB_PORT_ALL_INTERNAL RTL8366RB_PORT_CPU + +/* First configuration word per member config, VID and prio */ +#define RTL8366RB_VLAN_VID_MASK 0xfff +#define RTL8366RB_VLAN_PRIORITY_SHIFT 12 +#define RTL8366RB_VLAN_PRIORITY_MASK 0x7 +/* Second configuration word per member config, member and untagged */ +#define RTL8366RB_VLAN_UNTAG_SHIFT 8 +#define RTL8366RB_VLAN_UNTAG_MASK 0xff +#define RTL8366RB_VLAN_MEMBER_MASK 0xff +/* Third config word per member config, STAG currently unused */ +#define RTL8366RB_VLAN_STAG_MBR_MASK 0xff +#define RTL8366RB_VLAN_STAG_MBR_SHIFT 8 +#define RTL8366RB_VLAN_STAG_IDX_MASK 0x7 +#define RTL8366RB_VLAN_STAG_IDX_SHIFT 5 +#define RTL8366RB_VLAN_FID_MASK 0x7 + +/* Port ingress bandwidth control */ +#define RTL8366RB_IB_BASE 0x0200 +#define RTL8366RB_IB_REG(pnum) (RTL8366RB_IB_BASE + (pnum)) +#define RTL8366RB_IB_BDTH_MASK 0x3fff +#define RTL8366RB_IB_PREIFG BIT(14) + +/* Port egress bandwidth control */ +#define RTL8366RB_EB_BASE 0x02d1 +#define RTL8366RB_EB_REG(pnum) (RTL8366RB_EB_BASE + (pnum)) +#define RTL8366RB_EB_BDTH_MASK 0x3fff +#define RTL8366RB_EB_PREIFG_REG 0x02f8 +#define RTL8366RB_EB_PREIFG BIT(9) + +#define RTL8366RB_BDTH_SW_MAX 1048512 /* 1048576? */ +#define RTL8366RB_BDTH_UNIT 64 +#define RTL8366RB_BDTH_REG_DEFAULT 16383 + +/* QOS */ +#define RTL8366RB_QOS BIT(15) +/* Include/Exclude Preamble and IFG (20 bytes). 0:Exclude, 1:Include. */ +#define RTL8366RB_QOS_DEFAULT_PREIFG 1 + +/* Interrupt handling */ +#define RTL8366RB_INTERRUPT_CONTROL_REG 0x0440 +#define RTL8366RB_INTERRUPT_POLARITY BIT(0) +#define RTL8366RB_P4_RGMII_LED BIT(2) +#define RTL8366RB_INTERRUPT_MASK_REG 0x0441 +#define RTL8366RB_INTERRUPT_LINK_CHGALL GENMASK(11, 0) +#define RTL8366RB_INTERRUPT_ACLEXCEED BIT(8) +#define RTL8366RB_INTERRUPT_STORMEXCEED BIT(9) +#define RTL8366RB_INTERRUPT_P4_FIBER BIT(12) +#define RTL8366RB_INTERRUPT_P4_UTP BIT(13) +#define RTL8366RB_INTERRUPT_VALID (RTL8366RB_INTERRUPT_LINK_CHGALL | \ + RTL8366RB_INTERRUPT_ACLEXCEED | \ + RTL8366RB_INTERRUPT_STORMEXCEED | \ + RTL8366RB_INTERRUPT_P4_FIBER | \ + RTL8366RB_INTERRUPT_P4_UTP) +#define RTL8366RB_INTERRUPT_STATUS_REG 0x0442 +#define RTL8366RB_NUM_INTERRUPT 14 /* 0..13 */ + +/* Port isolation registers */ +#define RTL8366RB_PORT_ISO_BASE 0x0F08 +#define RTL8366RB_PORT_ISO(pnum) (RTL8366RB_PORT_ISO_BASE + (pnum)) +#define RTL8366RB_PORT_ISO_EN BIT(0) +#define RTL8366RB_PORT_ISO_PORTS_MASK GENMASK(7, 1) +#define RTL8366RB_PORT_ISO_PORTS(pmask) ((pmask) << 1) + +/* bits 0..5 enable force when cleared */ +#define RTL8366RB_MAC_FORCE_CTRL_REG 0x0F11 + +#define RTL8366RB_OAM_PARSER_REG 0x0F14 +#define RTL8366RB_OAM_MULTIPLEXER_REG 0x0F15 + +#define RTL8366RB_GREEN_FEATURE_REG 0x0F51 +#define RTL8366RB_GREEN_FEATURE_MSK 0x0007 +#define RTL8366RB_GREEN_FEATURE_TX BIT(0) +#define RTL8366RB_GREEN_FEATURE_RX BIT(2) + +/** + * struct rtl8366rb - RTL8366RB-specific data + * @max_mtu: per-port max MTU setting + * @pvid_enabled: if PVID is set for respective port + */ +struct rtl8366rb { + unsigned int max_mtu[RTL8366RB_NUM_PORTS]; + bool pvid_enabled[RTL8366RB_NUM_PORTS]; +}; + +static struct rtl8366_mib_counter rtl8366rb_mib_counters[] =3D { + { 0, 0, 4, "IfInOctets" }, + { 0, 4, 4, "EtherStatsOctets" }, + { 0, 8, 2, "EtherStatsUnderSizePkts" }, + { 0, 10, 2, "EtherFragments" }, + { 0, 12, 2, "EtherStatsPkts64Octets" }, + { 0, 14, 2, "EtherStatsPkts65to127Octets" }, + { 0, 16, 2, "EtherStatsPkts128to255Octets" }, + { 0, 18, 2, "EtherStatsPkts256to511Octets" }, + { 0, 20, 2, "EtherStatsPkts512to1023Octets" }, + { 0, 22, 2, "EtherStatsPkts1024to1518Octets" }, + { 0, 24, 2, "EtherOversizeStats" }, + { 0, 26, 2, "EtherStatsJabbers" }, + { 0, 28, 2, "IfInUcastPkts" }, + { 0, 30, 2, "EtherStatsMulticastPkts" }, + { 0, 32, 2, "EtherStatsBroadcastPkts" }, + { 0, 34, 2, "EtherStatsDropEvents" }, + { 0, 36, 2, "Dot3StatsFCSErrors" }, + { 0, 38, 2, "Dot3StatsSymbolErrors" }, + { 0, 40, 2, "Dot3InPauseFrames" }, + { 0, 42, 2, "Dot3ControlInUnknownOpcodes" }, + { 0, 44, 4, "IfOutOctets" }, + { 0, 48, 2, "Dot3StatsSingleCollisionFrames" }, + { 0, 50, 2, "Dot3StatMultipleCollisionFrames" }, + { 0, 52, 2, "Dot3sDeferredTransmissions" }, + { 0, 54, 2, "Dot3StatsLateCollisions" }, + { 0, 56, 2, "EtherStatsCollisions" }, + { 0, 58, 2, "Dot3StatsExcessiveCollisions" }, + { 0, 60, 2, "Dot3OutPauseFrames" }, + { 0, 62, 2, "Dot1dBasePortDelayExceededDiscards" }, + { 0, 64, 2, "Dot1dTpPortInDiscards" }, + { 0, 66, 2, "IfOutUcastPkts" }, + { 0, 68, 2, "IfOutMulticastPkts" }, + { 0, 70, 2, "IfOutBroadcastPkts" }, +}; + +static int rtl8366rb_get_mib_counter(struct realtek_smi *smi, + int port, + struct rtl8366_mib_counter *mib, + u64 *mibvalue) +{ + u32 addr, val; + int ret; + int i; + + addr =3D RTL8366RB_MIB_COUNTER_BASE + + RTL8366RB_MIB_COUNTER_PORT_OFFSET * (port) + + mib->offset; + + /* Writing access counter address first + * then ASIC will prepare 64bits counter wait for being retrived + */ + ret =3D regmap_write(smi->map, addr, 0); /* Write whatever */ + if (ret) + return ret; + + /* Read MIB control register */ + ret =3D regmap_read(smi->map, RTL8366RB_MIB_CTRL_REG, &val); + if (ret) + return -EIO; + + if (val & RTL8366RB_MIB_CTRL_BUSY_MASK) + return -EBUSY; + + if (val & RTL8366RB_MIB_CTRL_RESET_MASK) + return -EIO; + + /* Read each individual MIB 16 bits at the time */ + *mibvalue =3D 0; + for (i =3D mib->length; i > 0; i--) { + ret =3D regmap_read(smi->map, addr + (i - 1), &val); + if (ret) + return ret; + *mibvalue =3D (*mibvalue << 16) | (val & 0xFFFF); + } + return 0; +} + +static u32 rtl8366rb_get_irqmask(struct irq_data *d) +{ + int line =3D irqd_to_hwirq(d); + u32 val; + + /* For line interrupts we combine link down in bits + * 6..11 with link up in bits 0..5 into one interrupt. + */ + if (line < 12) + val =3D BIT(line) | BIT(line + 6); + else + val =3D BIT(line); + return val; +} + +static void rtl8366rb_mask_irq(struct irq_data *d) +{ + struct realtek_smi *smi =3D irq_data_get_irq_chip_data(d); + int ret; + + ret =3D regmap_update_bits(smi->map, RTL8366RB_INTERRUPT_MASK_REG, + rtl8366rb_get_irqmask(d), 0); + if (ret) + dev_err(smi->dev, "could not mask IRQ\n"); +} + +static void rtl8366rb_unmask_irq(struct irq_data *d) +{ + struct realtek_smi *smi =3D irq_data_get_irq_chip_data(d); + int ret; + + ret =3D regmap_update_bits(smi->map, RTL8366RB_INTERRUPT_MASK_REG, + rtl8366rb_get_irqmask(d), + rtl8366rb_get_irqmask(d)); + if (ret) + dev_err(smi->dev, "could not unmask IRQ\n"); +} + +static irqreturn_t rtl8366rb_irq(int irq, void *data) +{ + struct realtek_smi *smi =3D data; + u32 stat; + int ret; + + /* This clears the IRQ status register */ + ret =3D regmap_read(smi->map, RTL8366RB_INTERRUPT_STATUS_REG, + &stat); + if (ret) { + dev_err(smi->dev, "can't read interrupt status\n"); + return IRQ_NONE; + } + stat &=3D RTL8366RB_INTERRUPT_VALID; + if (!stat) + return IRQ_NONE; + while (stat) { + int line =3D __ffs(stat); + int child_irq; + + stat &=3D ~BIT(line); + /* For line interrupts we combine link down in bits + * 6..11 with link up in bits 0..5 into one interrupt. + */ + if (line < 12 && line > 5) + line -=3D 5; + child_irq =3D irq_find_mapping(smi->irqdomain, line); + handle_nested_irq(child_irq); + } + return IRQ_HANDLED; +} + +static struct irq_chip rtl8366rb_irq_chip =3D { + .name =3D "RTL8366RB", + .irq_mask =3D rtl8366rb_mask_irq, + .irq_unmask =3D rtl8366rb_unmask_irq, +}; + +static int rtl8366rb_irq_map(struct irq_domain *domain, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_set_chip_data(irq, domain->host_data); + irq_set_chip_and_handler(irq, &rtl8366rb_irq_chip, handle_simple_irq); + irq_set_nested_thread(irq, 1); + irq_set_noprobe(irq); + + return 0; +} + +static void rtl8366rb_irq_unmap(struct irq_domain *d, unsigned int irq) +{ + irq_set_nested_thread(irq, 0); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); +} + +static const struct irq_domain_ops rtl8366rb_irqdomain_ops =3D { + .map =3D rtl8366rb_irq_map, + .unmap =3D rtl8366rb_irq_unmap, + .xlate =3D irq_domain_xlate_onecell, +}; + +static int rtl8366rb_setup_cascaded_irq(struct realtek_smi *smi) +{ + struct device_node *intc; + unsigned long irq_trig; + int irq; + int ret; + u32 val; + int i; + + intc =3D of_get_child_by_name(smi->dev->of_node, "interrupt-controller"); + if (!intc) { + dev_err(smi->dev, "missing child interrupt-controller node\n"); + return -EINVAL; + } + /* RB8366RB IRQs cascade off this one */ + irq =3D of_irq_get(intc, 0); + if (irq <=3D 0) { + dev_err(smi->dev, "failed to get parent IRQ\n"); + ret =3D irq ? irq : -EINVAL; + goto out_put_node; + } + + /* This clears the IRQ status register */ + ret =3D regmap_read(smi->map, RTL8366RB_INTERRUPT_STATUS_REG, + &val); + if (ret) { + dev_err(smi->dev, "can't read interrupt status\n"); + goto out_put_node; + } + + /* Fetch IRQ edge information from the descriptor */ + irq_trig =3D irqd_get_trigger_type(irq_get_irq_data(irq)); + switch (irq_trig) { + case IRQF_TRIGGER_RISING: + case IRQF_TRIGGER_HIGH: + dev_info(smi->dev, "active high/rising IRQ\n"); + val =3D 0; + break; + case IRQF_TRIGGER_FALLING: + case IRQF_TRIGGER_LOW: + dev_info(smi->dev, "active low/falling IRQ\n"); + val =3D RTL8366RB_INTERRUPT_POLARITY; + break; + } + ret =3D regmap_update_bits(smi->map, RTL8366RB_INTERRUPT_CONTROL_REG, + RTL8366RB_INTERRUPT_POLARITY, + val); + if (ret) { + dev_err(smi->dev, "could not configure IRQ polarity\n"); + goto out_put_node; + } + + ret =3D devm_request_threaded_irq(smi->dev, irq, NULL, + rtl8366rb_irq, IRQF_ONESHOT, + "RTL8366RB", smi); + if (ret) { + dev_err(smi->dev, "unable to request irq: %d\n", ret); + goto out_put_node; + } + smi->irqdomain =3D irq_domain_add_linear(intc, + RTL8366RB_NUM_INTERRUPT, + &rtl8366rb_irqdomain_ops, + smi); + if (!smi->irqdomain) { + dev_err(smi->dev, "failed to create IRQ domain\n"); + ret =3D -EINVAL; + goto out_put_node; + } + for (i =3D 0; i < smi->num_ports; i++) + irq_set_parent(irq_create_mapping(smi->irqdomain, i), irq); + +out_put_node: + of_node_put(intc); + return ret; +} + +static int rtl8366rb_set_addr(struct realtek_smi *smi) +{ + u8 addr[ETH_ALEN]; + u16 val; + int ret; + + eth_random_addr(addr); + + dev_info(smi->dev, "set MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + val =3D addr[0] << 8 | addr[1]; + ret =3D regmap_write(smi->map, RTL8366RB_SMAR0, val); + if (ret) + return ret; + val =3D addr[2] << 8 | addr[3]; + ret =3D regmap_write(smi->map, RTL8366RB_SMAR1, val); + if (ret) + return ret; + val =3D addr[4] << 8 | addr[5]; + ret =3D regmap_write(smi->map, RTL8366RB_SMAR2, val); + if (ret) + return ret; + + return 0; +} + +/* Found in a vendor driver */ + +/* Struct for handling the jam tables' entries */ +struct rtl8366rb_jam_tbl_entry { + u16 reg; + u16 val; +}; + +/* For the "version 0" early silicon, appear in most source releases */ +static const struct rtl8366rb_jam_tbl_entry rtl8366rb_init_jam_ver_0[] =3D= { + {0x000B, 0x0001}, {0x03A6, 0x0100}, {0x03A7, 0x0001}, {0x02D1, 0x3FFF}, + {0x02D2, 0x3FFF}, {0x02D3, 0x3FFF}, {0x02D4, 0x3FFF}, {0x02D5, 0x3FFF}, + {0x02D6, 0x3FFF}, {0x02D7, 0x3FFF}, {0x02D8, 0x3FFF}, {0x022B, 0x0688}, + {0x022C, 0x0FAC}, {0x03D0, 0x4688}, {0x03D1, 0x01F5}, {0x0000, 0x0830}, + {0x02F9, 0x0200}, {0x02F7, 0x7FFF}, {0x02F8, 0x03FF}, {0x0080, 0x03E8}, + {0x0081, 0x00CE}, {0x0082, 0x00DA}, {0x0083, 0x0230}, {0xBE0F, 0x2000}, + {0x0231, 0x422A}, {0x0232, 0x422A}, {0x0233, 0x422A}, {0x0234, 0x422A}, + {0x0235, 0x422A}, {0x0236, 0x422A}, {0x0237, 0x422A}, {0x0238, 0x422A}, + {0x0239, 0x422A}, {0x023A, 0x422A}, {0x023B, 0x422A}, {0x023C, 0x422A}, + {0x023D, 0x422A}, {0x023E, 0x422A}, {0x023F, 0x422A}, {0x0240, 0x422A}, + {0x0241, 0x422A}, {0x0242, 0x422A}, {0x0243, 0x422A}, {0x0244, 0x422A}, + {0x0245, 0x422A}, {0x0246, 0x422A}, {0x0247, 0x422A}, {0x0248, 0x422A}, + {0x0249, 0x0146}, {0x024A, 0x0146}, {0x024B, 0x0146}, {0xBE03, 0xC961}, + {0x024D, 0x0146}, {0x024E, 0x0146}, {0x024F, 0x0146}, {0x0250, 0x0146}, + {0xBE64, 0x0226}, {0x0252, 0x0146}, {0x0253, 0x0146}, {0x024C, 0x0146}, + {0x0251, 0x0146}, {0x0254, 0x0146}, {0xBE62, 0x3FD0}, {0x0084, 0x0320}, + {0x0255, 0x0146}, {0x0256, 0x0146}, {0x0257, 0x0146}, {0x0258, 0x0146}, + {0x0259, 0x0146}, {0x025A, 0x0146}, {0x025B, 0x0146}, {0x025C, 0x0146}, + {0x025D, 0x0146}, {0x025E, 0x0146}, {0x025F, 0x0146}, {0x0260, 0x0146}, + {0x0261, 0xA23F}, {0x0262, 0x0294}, {0x0263, 0xA23F}, {0x0264, 0x0294}, + {0x0265, 0xA23F}, {0x0266, 0x0294}, {0x0267, 0xA23F}, {0x0268, 0x0294}, + {0x0269, 0xA23F}, {0x026A, 0x0294}, {0x026B, 0xA23F}, {0x026C, 0x0294}, + {0x026D, 0xA23F}, {0x026E, 0x0294}, {0x026F, 0xA23F}, {0x0270, 0x0294}, + {0x02F5, 0x0048}, {0xBE09, 0x0E00}, {0xBE1E, 0x0FA0}, {0xBE14, 0x8448}, + {0xBE15, 0x1007}, {0xBE4A, 0xA284}, {0xC454, 0x3F0B}, {0xC474, 0x3F0B}, + {0xBE48, 0x3672}, {0xBE4B, 0x17A7}, {0xBE4C, 0x0B15}, {0xBE52, 0x0EDD}, + {0xBE49, 0x8C00}, {0xBE5B, 0x785C}, {0xBE5C, 0x785C}, {0xBE5D, 0x785C}, + {0xBE61, 0x368A}, {0xBE63, 0x9B84}, {0xC456, 0xCC13}, {0xC476, 0xCC13}, + {0xBE65, 0x307D}, {0xBE6D, 0x0005}, {0xBE6E, 0xE120}, {0xBE2E, 0x7BAF}, +}; + +/* This v1 init sequence is from Belkin F5D8235 U-Boot release */ +static const struct rtl8366rb_jam_tbl_entry rtl8366rb_init_jam_ver_1[] =3D= { + {0x0000, 0x0830}, {0x0001, 0x8000}, {0x0400, 0x8130}, {0xBE78, 0x3C3C}, + {0x0431, 0x5432}, {0xBE37, 0x0CE4}, {0x02FA, 0xFFDF}, {0x02FB, 0xFFE0}, + {0xC44C, 0x1585}, {0xC44C, 0x1185}, {0xC44C, 0x1585}, {0xC46C, 0x1585}, + {0xC46C, 0x1185}, {0xC46C, 0x1585}, {0xC451, 0x2135}, {0xC471, 0x2135}, + {0xBE10, 0x8140}, {0xBE15, 0x0007}, {0xBE6E, 0xE120}, {0xBE69, 0xD20F}, + {0xBE6B, 0x0320}, {0xBE24, 0xB000}, {0xBE23, 0xFF51}, {0xBE22, 0xDF20}, + {0xBE21, 0x0140}, {0xBE20, 0x00BB}, {0xBE24, 0xB800}, {0xBE24, 0x0000}, + {0xBE24, 0x7000}, {0xBE23, 0xFF51}, {0xBE22, 0xDF60}, {0xBE21, 0x0140}, + {0xBE20, 0x0077}, {0xBE24, 0x7800}, {0xBE24, 0x0000}, {0xBE2E, 0x7B7A}, + {0xBE36, 0x0CE4}, {0x02F5, 0x0048}, {0xBE77, 0x2940}, {0x000A, 0x83E0}, + {0xBE79, 0x3C3C}, {0xBE00, 0x1340}, +}; + +/* This v2 init sequence is from Belkin F5D8235 U-Boot release */ +static const struct rtl8366rb_jam_tbl_entry rtl8366rb_init_jam_ver_2[] =3D= { + {0x0450, 0x0000}, {0x0400, 0x8130}, {0x000A, 0x83ED}, {0x0431, 0x5432}, + {0xC44F, 0x6250}, {0xC46F, 0x6250}, {0xC456, 0x0C14}, {0xC476, 0x0C14}, + {0xC44C, 0x1C85}, {0xC44C, 0x1885}, {0xC44C, 0x1C85}, {0xC46C, 0x1C85}, + {0xC46C, 0x1885}, {0xC46C, 0x1C85}, {0xC44C, 0x0885}, {0xC44C, 0x0881}, + {0xC44C, 0x0885}, {0xC46C, 0x0885}, {0xC46C, 0x0881}, {0xC46C, 0x0885}, + {0xBE2E, 0x7BA7}, {0xBE36, 0x1000}, {0xBE37, 0x1000}, {0x8000, 0x0001}, + {0xBE69, 0xD50F}, {0x8000, 0x0000}, {0xBE69, 0xD50F}, {0xBE6E, 0x0320}, + {0xBE77, 0x2940}, {0xBE78, 0x3C3C}, {0xBE79, 0x3C3C}, {0xBE6E, 0xE120}, + {0x8000, 0x0001}, {0xBE15, 0x1007}, {0x8000, 0x0000}, {0xBE15, 0x1007}, + {0xBE14, 0x0448}, {0xBE1E, 0x00A0}, {0xBE10, 0x8160}, {0xBE10, 0x8140}, + {0xBE00, 0x1340}, {0x0F51, 0x0010}, +}; + +/* Appears in a DDWRT code dump */ +static const struct rtl8366rb_jam_tbl_entry rtl8366rb_init_jam_ver_3[] =3D= { + {0x0000, 0x0830}, {0x0400, 0x8130}, {0x000A, 0x83ED}, {0x0431, 0x5432}, + {0x0F51, 0x0017}, {0x02F5, 0x0048}, {0x02FA, 0xFFDF}, {0x02FB, 0xFFE0}, + {0xC456, 0x0C14}, {0xC476, 0x0C14}, {0xC454, 0x3F8B}, {0xC474, 0x3F8B}, + {0xC450, 0x2071}, {0xC470, 0x2071}, {0xC451, 0x226B}, {0xC471, 0x226B}, + {0xC452, 0xA293}, {0xC472, 0xA293}, {0xC44C, 0x1585}, {0xC44C, 0x1185}, + {0xC44C, 0x1585}, {0xC46C, 0x1585}, {0xC46C, 0x1185}, {0xC46C, 0x1585}, + {0xC44C, 0x0185}, {0xC44C, 0x0181}, {0xC44C, 0x0185}, {0xC46C, 0x0185}, + {0xC46C, 0x0181}, {0xC46C, 0x0185}, {0xBE24, 0xB000}, {0xBE23, 0xFF51}, + {0xBE22, 0xDF20}, {0xBE21, 0x0140}, {0xBE20, 0x00BB}, {0xBE24, 0xB800}, + {0xBE24, 0x0000}, {0xBE24, 0x7000}, {0xBE23, 0xFF51}, {0xBE22, 0xDF60}, + {0xBE21, 0x0140}, {0xBE20, 0x0077}, {0xBE24, 0x7800}, {0xBE24, 0x0000}, + {0xBE2E, 0x7BA7}, {0xBE36, 0x1000}, {0xBE37, 0x1000}, {0x8000, 0x0001}, + {0xBE69, 0xD50F}, {0x8000, 0x0000}, {0xBE69, 0xD50F}, {0xBE6B, 0x0320}, + {0xBE77, 0x2800}, {0xBE78, 0x3C3C}, {0xBE79, 0x3C3C}, {0xBE6E, 0xE120}, + {0x8000, 0x0001}, {0xBE10, 0x8140}, {0x8000, 0x0000}, {0xBE10, 0x8140}, + {0xBE15, 0x1007}, {0xBE14, 0x0448}, {0xBE1E, 0x00A0}, {0xBE10, 0x8160}, + {0xBE10, 0x8140}, {0xBE00, 0x1340}, {0x0450, 0x0000}, {0x0401, 0x0000}, +}; + +/* Belkin F5D8235 v1, "belkin,f5d8235-v1" */ +static const struct rtl8366rb_jam_tbl_entry rtl8366rb_init_jam_f5d8235[] = =3D { + {0x0242, 0x02BF}, {0x0245, 0x02BF}, {0x0248, 0x02BF}, {0x024B, 0x02BF}, + {0x024E, 0x02BF}, {0x0251, 0x02BF}, {0x0254, 0x0A3F}, {0x0256, 0x0A3F}, + {0x0258, 0x0A3F}, {0x025A, 0x0A3F}, {0x025C, 0x0A3F}, {0x025E, 0x0A3F}, + {0x0263, 0x007C}, {0x0100, 0x0004}, {0xBE5B, 0x3500}, {0x800E, 0x200F}, + {0xBE1D, 0x0F00}, {0x8001, 0x5011}, {0x800A, 0xA2F4}, {0x800B, 0x17A3}, + {0xBE4B, 0x17A3}, {0xBE41, 0x5011}, {0xBE17, 0x2100}, {0x8000, 0x8304}, + {0xBE40, 0x8304}, {0xBE4A, 0xA2F4}, {0x800C, 0xA8D5}, {0x8014, 0x5500}, + {0x8015, 0x0004}, {0xBE4C, 0xA8D5}, {0xBE59, 0x0008}, {0xBE09, 0x0E00}, + {0xBE36, 0x1036}, {0xBE37, 0x1036}, {0x800D, 0x00FF}, {0xBE4D, 0x00FF}, +}; + +/* DGN3500, "netgear,dgn3500", "netgear,dgn3500b" */ +static const struct rtl8366rb_jam_tbl_entry rtl8366rb_init_jam_dgn3500[] = =3D { + {0x0000, 0x0830}, {0x0400, 0x8130}, {0x000A, 0x83ED}, {0x0F51, 0x0017}, + {0x02F5, 0x0048}, {0x02FA, 0xFFDF}, {0x02FB, 0xFFE0}, {0x0450, 0x0000}, + {0x0401, 0x0000}, {0x0431, 0x0960}, +}; + +/* This jam table activates "green ethernet", which means low power mode + * and is claimed to detect the cable length and not use more power than + * necessary, and the ports should enter power saving mode 10 seconds after + * a cable is disconnected. Seems to always be the same. + */ +static const struct rtl8366rb_jam_tbl_entry rtl8366rb_green_jam[] =3D { + {0xBE78, 0x323C}, {0xBE77, 0x5000}, {0xBE2E, 0x7BA7}, + {0xBE59, 0x3459}, {0xBE5A, 0x745A}, {0xBE5B, 0x785C}, + {0xBE5C, 0x785C}, {0xBE6E, 0xE120}, {0xBE79, 0x323C}, +}; + +/* Function that jams the tables in the proper registers */ +static int rtl8366rb_jam_table(const struct rtl8366rb_jam_tbl_entry *jam_t= able, + int jam_size, struct realtek_smi *smi, + bool write_dbg) +{ + u32 val; + int ret; + int i; + + for (i =3D 0; i < jam_size; i++) { + if ((jam_table[i].reg & 0xBE00) =3D=3D 0xBE00) { + ret =3D regmap_read(smi->map, + RTL8366RB_PHY_ACCESS_BUSY_REG, + &val); + if (ret) + return ret; + if (!(val & RTL8366RB_PHY_INT_BUSY)) { + ret =3D regmap_write(smi->map, + RTL8366RB_PHY_ACCESS_CTRL_REG, + RTL8366RB_PHY_CTRL_WRITE); + if (ret) + return ret; + } + } + if (write_dbg) + dev_dbg(smi->dev, "jam %04x into register %04x\n", + jam_table[i].val, + jam_table[i].reg); + ret =3D regmap_write(smi->map, + jam_table[i].reg, + jam_table[i].val); + if (ret) + return ret; + } + return 0; +} + +static int rtl8366rb_setup(struct dsa_switch *ds) +{ + struct realtek_smi *smi =3D ds->priv; + const struct rtl8366rb_jam_tbl_entry *jam_table; + struct rtl8366rb *rb; + u32 chip_ver =3D 0; + u32 chip_id =3D 0; + int jam_size; + u32 val; + int ret; + int i; + + rb =3D smi->chip_data; + + ret =3D regmap_read(smi->map, RTL8366RB_CHIP_ID_REG, &chip_id); + if (ret) { + dev_err(smi->dev, "unable to read chip id\n"); + return ret; + } + + switch (chip_id) { + case RTL8366RB_CHIP_ID_8366: + break; + default: + dev_err(smi->dev, "unknown chip id (%04x)\n", chip_id); + return -ENODEV; + } + + ret =3D regmap_read(smi->map, RTL8366RB_CHIP_VERSION_CTRL_REG, + &chip_ver); + if (ret) { + dev_err(smi->dev, "unable to read chip version\n"); + return ret; + } + + dev_info(smi->dev, "RTL%04x ver %u chip found\n", + chip_id, chip_ver & RTL8366RB_CHIP_VERSION_MASK); + + /* Do the init dance using the right jam table */ + switch (chip_ver) { + case 0: + jam_table =3D rtl8366rb_init_jam_ver_0; + jam_size =3D ARRAY_SIZE(rtl8366rb_init_jam_ver_0); + break; + case 1: + jam_table =3D rtl8366rb_init_jam_ver_1; + jam_size =3D ARRAY_SIZE(rtl8366rb_init_jam_ver_1); + break; + case 2: + jam_table =3D rtl8366rb_init_jam_ver_2; + jam_size =3D ARRAY_SIZE(rtl8366rb_init_jam_ver_2); + break; + default: + jam_table =3D rtl8366rb_init_jam_ver_3; + jam_size =3D ARRAY_SIZE(rtl8366rb_init_jam_ver_3); + break; + } + + /* Special jam tables for special routers + * TODO: are these necessary? Maintainers, please test + * without them, using just the off-the-shelf tables. + */ + if (of_machine_is_compatible("belkin,f5d8235-v1")) { + jam_table =3D rtl8366rb_init_jam_f5d8235; + jam_size =3D ARRAY_SIZE(rtl8366rb_init_jam_f5d8235); + } + if (of_machine_is_compatible("netgear,dgn3500") || + of_machine_is_compatible("netgear,dgn3500b")) { + jam_table =3D rtl8366rb_init_jam_dgn3500; + jam_size =3D ARRAY_SIZE(rtl8366rb_init_jam_dgn3500); + } + + ret =3D rtl8366rb_jam_table(jam_table, jam_size, smi, true); + if (ret) + return ret; + + /* Isolate all user ports so they can only send packets to itself and the= CPU port */ + for (i =3D 0; i < RTL8366RB_PORT_NUM_CPU; i++) { + ret =3D regmap_write(smi->map, RTL8366RB_PORT_ISO(i), + RTL8366RB_PORT_ISO_PORTS(BIT(RTL8366RB_PORT_NUM_CPU)) | + RTL8366RB_PORT_ISO_EN); + if (ret) + return ret; + } + /* CPU port can send packets to all ports */ + ret =3D regmap_write(smi->map, RTL8366RB_PORT_ISO(RTL8366RB_PORT_NUM_CPU), + RTL8366RB_PORT_ISO_PORTS(dsa_user_ports(ds)) | + RTL8366RB_PORT_ISO_EN); + if (ret) + return ret; + + /* Set up the "green ethernet" feature */ + ret =3D rtl8366rb_jam_table(rtl8366rb_green_jam, + ARRAY_SIZE(rtl8366rb_green_jam), smi, false); + if (ret) + return ret; + + ret =3D regmap_write(smi->map, + RTL8366RB_GREEN_FEATURE_REG, + (chip_ver =3D=3D 1) ? 0x0007 : 0x0003); + if (ret) + return ret; + + /* Vendor driver sets 0x240 in registers 0xc and 0xd (undocumented) */ + ret =3D regmap_write(smi->map, 0x0c, 0x240); + if (ret) + return ret; + ret =3D regmap_write(smi->map, 0x0d, 0x240); + if (ret) + return ret; + + /* Set some random MAC address */ + ret =3D rtl8366rb_set_addr(smi); + if (ret) + return ret; + + /* Enable CPU port with custom DSA tag 8899. + * + * If you set RTL8368RB_CPU_NO_TAG (bit 15) in this registers + * the custom tag is turned off. + */ + ret =3D regmap_update_bits(smi->map, RTL8368RB_CPU_CTRL_REG, + 0xFFFF, + BIT(smi->cpu_port)); + if (ret) + return ret; + + /* Make sure we default-enable the fixed CPU port */ + ret =3D regmap_update_bits(smi->map, RTL8366RB_PECR, + BIT(smi->cpu_port), + 0); + if (ret) + return ret; + + /* Set maximum packet length to 1536 bytes */ + ret =3D regmap_update_bits(smi->map, RTL8366RB_SGCR, + RTL8366RB_SGCR_MAX_LENGTH_MASK, + RTL8366RB_SGCR_MAX_LENGTH_1536); + if (ret) + return ret; + for (i =3D 0; i < RTL8366RB_NUM_PORTS; i++) + /* layer 2 size, see rtl8366rb_change_mtu() */ + rb->max_mtu[i] =3D 1532; + + /* Disable learning for all ports */ + ret =3D regmap_write(smi->map, RTL8366RB_PORT_LEARNDIS_CTRL, + RTL8366RB_PORT_ALL); + if (ret) + return ret; + + /* Enable auto ageing for all ports */ + ret =3D regmap_write(smi->map, RTL8366RB_SECURITY_CTRL, 0); + if (ret) + return ret; + + /* Port 4 setup: this enables Port 4, usually the WAN port, + * common PHY IO mode is apparently mode 0, and this is not what + * the port is initialized to. There is no explanation of the + * IO modes in the Realtek source code, if your WAN port is + * connected to something exotic such as fiber, then this might + * be worth experimenting with. + */ + ret =3D regmap_update_bits(smi->map, RTL8366RB_PMC0, + RTL8366RB_PMC0_P4_IOMODE_MASK, + 0 << RTL8366RB_PMC0_P4_IOMODE_SHIFT); + if (ret) + return ret; + + /* Accept all packets by default, we enable filtering on-demand */ + ret =3D regmap_write(smi->map, RTL8366RB_VLAN_INGRESS_CTRL1_REG, + 0); + if (ret) + return ret; + ret =3D regmap_write(smi->map, RTL8366RB_VLAN_INGRESS_CTRL2_REG, + 0); + if (ret) + return ret; + + /* Don't drop packets whose DA has not been learned */ + ret =3D regmap_update_bits(smi->map, RTL8366RB_SSCR2, + RTL8366RB_SSCR2_DROP_UNKNOWN_DA, 0); + if (ret) + return ret; + + /* Set blinking, TODO: make this configurable */ + ret =3D regmap_update_bits(smi->map, RTL8366RB_LED_BLINKRATE_REG, + RTL8366RB_LED_BLINKRATE_MASK, + RTL8366RB_LED_BLINKRATE_56MS); + if (ret) + return ret; + + /* Set up LED activity: + * Each port has 4 LEDs, we configure all ports to the same + * behaviour (no individual config) but we can set up each + * LED separately. + */ + if (smi->leds_disabled) { + /* Turn everything off */ + regmap_update_bits(smi->map, + RTL8366RB_LED_0_1_CTRL_REG, + 0x0FFF, 0); + regmap_update_bits(smi->map, + RTL8366RB_LED_2_3_CTRL_REG, + 0x0FFF, 0); + regmap_update_bits(smi->map, + RTL8366RB_INTERRUPT_CONTROL_REG, + RTL8366RB_P4_RGMII_LED, + 0); + val =3D RTL8366RB_LED_OFF; + } else { + /* TODO: make this configurable per LED */ + val =3D RTL8366RB_LED_FORCE; + } + for (i =3D 0; i < 4; i++) { + ret =3D regmap_update_bits(smi->map, + RTL8366RB_LED_CTRL_REG, + 0xf << (i * 4), + val << (i * 4)); + if (ret) + return ret; + } + + ret =3D rtl8366_reset_vlan(smi); + if (ret) + return ret; + + ret =3D rtl8366rb_setup_cascaded_irq(smi); + if (ret) + dev_info(smi->dev, "no interrupt support\n"); + + ret =3D realtek_smi_setup_mdio(smi); + if (ret) { + dev_info(smi->dev, "could not set up MDIO bus\n"); + return -ENODEV; + } + + return 0; +} + +static enum dsa_tag_protocol rtl8366_get_tag_protocol(struct dsa_switch *d= s, + int port, + enum dsa_tag_protocol mp) +{ + /* This switch uses the 4 byte protocol A Realtek DSA tag */ + return DSA_TAG_PROTO_RTL4_A; +} + +static void +rtl8366rb_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, + phy_interface_t interface, struct phy_device *phydev, + int speed, int duplex, bool tx_pause, bool rx_pause) +{ + struct realtek_smi *smi =3D ds->priv; + int ret; + + if (port !=3D smi->cpu_port) + return; + + dev_dbg(smi->dev, "MAC link up on CPU port (%d)\n", port); + + /* Force the fixed CPU port into 1Gbit mode, no autonegotiation */ + ret =3D regmap_update_bits(smi->map, RTL8366RB_MAC_FORCE_CTRL_REG, + BIT(port), BIT(port)); + if (ret) { + dev_err(smi->dev, "failed to force 1Gbit on CPU port\n"); + return; + } + + ret =3D regmap_update_bits(smi->map, RTL8366RB_PAACR2, + 0xFF00U, + RTL8366RB_PAACR_CPU_PORT << 8); + if (ret) { + dev_err(smi->dev, "failed to set PAACR on CPU port\n"); + return; + } + + /* Enable the CPU port */ + ret =3D regmap_update_bits(smi->map, RTL8366RB_PECR, BIT(port), + 0); + if (ret) { + dev_err(smi->dev, "failed to enable the CPU port\n"); + return; + } +} + +static void +rtl8366rb_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, + phy_interface_t interface) +{ + struct realtek_smi *smi =3D ds->priv; + int ret; + + if (port !=3D smi->cpu_port) + return; + + dev_dbg(smi->dev, "MAC link down on CPU port (%d)\n", port); + + /* Disable the CPU port */ + ret =3D regmap_update_bits(smi->map, RTL8366RB_PECR, BIT(port), + BIT(port)); + if (ret) { + dev_err(smi->dev, "failed to disable the CPU port\n"); + return; + } +} + +static void rb8366rb_set_port_led(struct realtek_smi *smi, + int port, bool enable) +{ + u16 val =3D enable ? 0x3f : 0; + int ret; + + if (smi->leds_disabled) + return; + + switch (port) { + case 0: + ret =3D regmap_update_bits(smi->map, + RTL8366RB_LED_0_1_CTRL_REG, + 0x3F, val); + break; + case 1: + ret =3D regmap_update_bits(smi->map, + RTL8366RB_LED_0_1_CTRL_REG, + 0x3F << RTL8366RB_LED_1_OFFSET, + val << RTL8366RB_LED_1_OFFSET); + break; + case 2: + ret =3D regmap_update_bits(smi->map, + RTL8366RB_LED_2_3_CTRL_REG, + 0x3F, val); + break; + case 3: + ret =3D regmap_update_bits(smi->map, + RTL8366RB_LED_2_3_CTRL_REG, + 0x3F << RTL8366RB_LED_3_OFFSET, + val << RTL8366RB_LED_3_OFFSET); + break; + case 4: + ret =3D regmap_update_bits(smi->map, + RTL8366RB_INTERRUPT_CONTROL_REG, + RTL8366RB_P4_RGMII_LED, + enable ? RTL8366RB_P4_RGMII_LED : 0); + break; + default: + dev_err(smi->dev, "no LED for port %d\n", port); + return; + } + if (ret) + dev_err(smi->dev, "error updating LED on port %d\n", port); +} + +static int +rtl8366rb_port_enable(struct dsa_switch *ds, int port, + struct phy_device *phy) +{ + struct realtek_smi *smi =3D ds->priv; + int ret; + + dev_dbg(smi->dev, "enable port %d\n", port); + ret =3D regmap_update_bits(smi->map, RTL8366RB_PECR, BIT(port), + 0); + if (ret) + return ret; + + rb8366rb_set_port_led(smi, port, true); + return 0; +} + +static void +rtl8366rb_port_disable(struct dsa_switch *ds, int port) +{ + struct realtek_smi *smi =3D ds->priv; + int ret; + + dev_dbg(smi->dev, "disable port %d\n", port); + ret =3D regmap_update_bits(smi->map, RTL8366RB_PECR, BIT(port), + BIT(port)); + if (ret) + return; + + rb8366rb_set_port_led(smi, port, false); +} + +static int +rtl8366rb_port_bridge_join(struct dsa_switch *ds, int port, + struct net_device *bridge) +{ + struct realtek_smi *smi =3D ds->priv; + unsigned int port_bitmap =3D 0; + int ret, i; + + /* Loop over all other ports than the current one */ + for (i =3D 0; i < RTL8366RB_PORT_NUM_CPU; i++) { + /* Current port handled last */ + if (i =3D=3D port) + continue; + /* Not on this bridge */ + if (dsa_to_port(ds, i)->bridge_dev !=3D bridge) + continue; + /* Join this port to each other port on the bridge */ + ret =3D regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(i), + RTL8366RB_PORT_ISO_PORTS(BIT(port)), + RTL8366RB_PORT_ISO_PORTS(BIT(port))); + if (ret) + dev_err(smi->dev, "failed to join port %d\n", port); + + port_bitmap |=3D BIT(i); + } + + /* Set the bits for the ports we can access */ + return regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(port), + RTL8366RB_PORT_ISO_PORTS(port_bitmap), + RTL8366RB_PORT_ISO_PORTS(port_bitmap)); +} + +static void +rtl8366rb_port_bridge_leave(struct dsa_switch *ds, int port, + struct net_device *bridge) +{ + struct realtek_smi *smi =3D ds->priv; + unsigned int port_bitmap =3D 0; + int ret, i; + + /* Loop over all other ports than this one */ + for (i =3D 0; i < RTL8366RB_PORT_NUM_CPU; i++) { + /* Current port handled last */ + if (i =3D=3D port) + continue; + /* Not on this bridge */ + if (dsa_to_port(ds, i)->bridge_dev !=3D bridge) + continue; + /* Remove this port from any other port on the bridge */ + ret =3D regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(i), + RTL8366RB_PORT_ISO_PORTS(BIT(port)), 0); + if (ret) + dev_err(smi->dev, "failed to leave port %d\n", port); + + port_bitmap |=3D BIT(i); + } + + /* Clear the bits for the ports we can not access, leave ourselves */ + regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(port), + RTL8366RB_PORT_ISO_PORTS(port_bitmap), 0); +} + +/** + * rtl8366rb_drop_untagged() - make the switch drop untagged and C-tagged = frames + * @smi: SMI state container + * @port: the port to drop untagged and C-tagged frames on + * @drop: whether to drop or pass untagged and C-tagged frames + * + * Return: zero for success, a negative number on error. + */ +static int rtl8366rb_drop_untagged(struct realtek_smi *smi, int port, bool= drop) +{ + return regmap_update_bits(smi->map, RTL8366RB_VLAN_INGRESS_CTRL1_REG, + RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port), + drop ? RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port) : 0); +} + +static int rtl8366rb_vlan_filtering(struct dsa_switch *ds, int port, + bool vlan_filtering, + struct netlink_ext_ack *extack) +{ + struct realtek_smi *smi =3D ds->priv; + struct rtl8366rb *rb; + int ret; + + rb =3D smi->chip_data; + + dev_dbg(smi->dev, "port %d: %s VLAN filtering\n", port, + vlan_filtering ? "enable" : "disable"); + + /* If the port is not in the member set, the frame will be dropped */ + ret =3D regmap_update_bits(smi->map, RTL8366RB_VLAN_INGRESS_CTRL2_REG, + BIT(port), vlan_filtering ? BIT(port) : 0); + if (ret) + return ret; + + /* If VLAN filtering is enabled and PVID is also enabled, we must + * not drop any untagged or C-tagged frames. If we turn off VLAN + * filtering on a port, we need to accept any frames. + */ + if (vlan_filtering) + ret =3D rtl8366rb_drop_untagged(smi, port, !rb->pvid_enabled[port]); + else + ret =3D rtl8366rb_drop_untagged(smi, port, false); + + return ret; +} + +static int +rtl8366rb_port_pre_bridge_flags(struct dsa_switch *ds, int port, + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack) +{ + /* We support enabling/disabling learning */ + if (flags.mask & ~(BR_LEARNING)) + return -EINVAL; + + return 0; +} + +static int +rtl8366rb_port_bridge_flags(struct dsa_switch *ds, int port, + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack) +{ + struct realtek_smi *smi =3D ds->priv; + int ret; + + if (flags.mask & BR_LEARNING) { + ret =3D regmap_update_bits(smi->map, RTL8366RB_PORT_LEARNDIS_CTRL, + BIT(port), + (flags.val & BR_LEARNING) ? 0 : BIT(port)); + if (ret) + return ret; + } + + return 0; +} + +static void +rtl8366rb_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) +{ + struct realtek_smi *smi =3D ds->priv; + u32 val; + int i; + + switch (state) { + case BR_STATE_DISABLED: + val =3D RTL8366RB_STP_STATE_DISABLED; + break; + case BR_STATE_BLOCKING: + case BR_STATE_LISTENING: + val =3D RTL8366RB_STP_STATE_BLOCKING; + break; + case BR_STATE_LEARNING: + val =3D RTL8366RB_STP_STATE_LEARNING; + break; + case BR_STATE_FORWARDING: + val =3D RTL8366RB_STP_STATE_FORWARDING; + break; + default: + dev_err(smi->dev, "unknown bridge state requested\n"); + return; + } + + /* Set the same status for the port on all the FIDs */ + for (i =3D 0; i < RTL8366RB_NUM_FIDS; i++) { + regmap_update_bits(smi->map, RTL8366RB_STP_STATE_BASE + i, + RTL8366RB_STP_STATE_MASK(port), + RTL8366RB_STP_STATE(port, val)); + } +} + +static void +rtl8366rb_port_fast_age(struct dsa_switch *ds, int port) +{ + struct realtek_smi *smi =3D ds->priv; + + /* This will age out any learned L2 entries */ + regmap_update_bits(smi->map, RTL8366RB_SECURITY_CTRL, + BIT(port), BIT(port)); + /* Restore the normal state of things */ + regmap_update_bits(smi->map, RTL8366RB_SECURITY_CTRL, + BIT(port), 0); +} + +static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_m= tu) +{ + struct realtek_smi *smi =3D ds->priv; + struct rtl8366rb *rb; + unsigned int max_mtu; + u32 len; + int i; + + /* Cache the per-port MTU setting */ + rb =3D smi->chip_data; + rb->max_mtu[port] =3D new_mtu; + + /* Roof out the MTU for the entire switch to the greatest + * common denominator: the biggest set for any one port will + * be the biggest MTU for the switch. + * + * The first setting, 1522 bytes, is max IP packet 1500 bytes, + * plus ethernet header, 1518 bytes, plus CPU tag, 4 bytes. + * This function should consider the parameter an SDU, so the + * MTU passed for this setting is 1518 bytes. The same logic + * of subtracting the DSA tag of 4 bytes apply to the other + * settings. + */ + max_mtu =3D 1518; + for (i =3D 0; i < RTL8366RB_NUM_PORTS; i++) { + if (rb->max_mtu[i] > max_mtu) + max_mtu =3D rb->max_mtu[i]; + } + if (max_mtu <=3D 1518) + len =3D RTL8366RB_SGCR_MAX_LENGTH_1522; + else if (max_mtu > 1518 && max_mtu <=3D 1532) + len =3D RTL8366RB_SGCR_MAX_LENGTH_1536; + else if (max_mtu > 1532 && max_mtu <=3D 1548) + len =3D RTL8366RB_SGCR_MAX_LENGTH_1552; + else + len =3D RTL8366RB_SGCR_MAX_LENGTH_16000; + + return regmap_update_bits(smi->map, RTL8366RB_SGCR, + RTL8366RB_SGCR_MAX_LENGTH_MASK, + len); +} + +static int rtl8366rb_max_mtu(struct dsa_switch *ds, int port) +{ + /* The max MTU is 16000 bytes, so we subtract the CPU tag + * and the max presented to the system is 15996 bytes. + */ + return 15996; +} + +static int rtl8366rb_get_vlan_4k(struct realtek_smi *smi, u32 vid, + struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[3]; + int ret; + int i; + + memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); + + if (vid >=3D RTL8366RB_NUM_VIDS) + return -EINVAL; + + /* write VID */ + ret =3D regmap_write(smi->map, RTL8366RB_VLAN_TABLE_WRITE_BASE, + vid & RTL8366RB_VLAN_VID_MASK); + if (ret) + return ret; + + /* write table access control word */ + ret =3D regmap_write(smi->map, RTL8366RB_TABLE_ACCESS_CTRL_REG, + RTL8366RB_TABLE_VLAN_READ_CTRL); + if (ret) + return ret; + + for (i =3D 0; i < 3; i++) { + ret =3D regmap_read(smi->map, + RTL8366RB_VLAN_TABLE_READ_BASE + i, + &data[i]); + if (ret) + return ret; + } + + vlan4k->vid =3D vid; + vlan4k->untag =3D (data[1] >> RTL8366RB_VLAN_UNTAG_SHIFT) & + RTL8366RB_VLAN_UNTAG_MASK; + vlan4k->member =3D data[1] & RTL8366RB_VLAN_MEMBER_MASK; + vlan4k->fid =3D data[2] & RTL8366RB_VLAN_FID_MASK; + + return 0; +} + +static int rtl8366rb_set_vlan_4k(struct realtek_smi *smi, + const struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[3]; + int ret; + int i; + + if (vlan4k->vid >=3D RTL8366RB_NUM_VIDS || + vlan4k->member > RTL8366RB_VLAN_MEMBER_MASK || + vlan4k->untag > RTL8366RB_VLAN_UNTAG_MASK || + vlan4k->fid > RTL8366RB_FIDMAX) + return -EINVAL; + + data[0] =3D vlan4k->vid & RTL8366RB_VLAN_VID_MASK; + data[1] =3D (vlan4k->member & RTL8366RB_VLAN_MEMBER_MASK) | + ((vlan4k->untag & RTL8366RB_VLAN_UNTAG_MASK) << + RTL8366RB_VLAN_UNTAG_SHIFT); + data[2] =3D vlan4k->fid & RTL8366RB_VLAN_FID_MASK; + + for (i =3D 0; i < 3; i++) { + ret =3D regmap_write(smi->map, + RTL8366RB_VLAN_TABLE_WRITE_BASE + i, + data[i]); + if (ret) + return ret; + } + + /* write table access control word */ + ret =3D regmap_write(smi->map, RTL8366RB_TABLE_ACCESS_CTRL_REG, + RTL8366RB_TABLE_VLAN_WRITE_CTRL); + + return ret; +} + +static int rtl8366rb_get_vlan_mc(struct realtek_smi *smi, u32 index, + struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[3]; + int ret; + int i; + + memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); + + if (index >=3D RTL8366RB_NUM_VLANS) + return -EINVAL; + + for (i =3D 0; i < 3; i++) { + ret =3D regmap_read(smi->map, + RTL8366RB_VLAN_MC_BASE(index) + i, + &data[i]); + if (ret) + return ret; + } + + vlanmc->vid =3D data[0] & RTL8366RB_VLAN_VID_MASK; + vlanmc->priority =3D (data[0] >> RTL8366RB_VLAN_PRIORITY_SHIFT) & + RTL8366RB_VLAN_PRIORITY_MASK; + vlanmc->untag =3D (data[1] >> RTL8366RB_VLAN_UNTAG_SHIFT) & + RTL8366RB_VLAN_UNTAG_MASK; + vlanmc->member =3D data[1] & RTL8366RB_VLAN_MEMBER_MASK; + vlanmc->fid =3D data[2] & RTL8366RB_VLAN_FID_MASK; + + return 0; +} + +static int rtl8366rb_set_vlan_mc(struct realtek_smi *smi, u32 index, + const struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[3]; + int ret; + int i; + + if (index >=3D RTL8366RB_NUM_VLANS || + vlanmc->vid >=3D RTL8366RB_NUM_VIDS || + vlanmc->priority > RTL8366RB_PRIORITYMAX || + vlanmc->member > RTL8366RB_VLAN_MEMBER_MASK || + vlanmc->untag > RTL8366RB_VLAN_UNTAG_MASK || + vlanmc->fid > RTL8366RB_FIDMAX) + return -EINVAL; + + data[0] =3D (vlanmc->vid & RTL8366RB_VLAN_VID_MASK) | + ((vlanmc->priority & RTL8366RB_VLAN_PRIORITY_MASK) << + RTL8366RB_VLAN_PRIORITY_SHIFT); + data[1] =3D (vlanmc->member & RTL8366RB_VLAN_MEMBER_MASK) | + ((vlanmc->untag & RTL8366RB_VLAN_UNTAG_MASK) << + RTL8366RB_VLAN_UNTAG_SHIFT); + data[2] =3D vlanmc->fid & RTL8366RB_VLAN_FID_MASK; + + for (i =3D 0; i < 3; i++) { + ret =3D regmap_write(smi->map, + RTL8366RB_VLAN_MC_BASE(index) + i, + data[i]); + if (ret) + return ret; + } + + return 0; +} + +static int rtl8366rb_get_mc_index(struct realtek_smi *smi, int port, int *= val) +{ + u32 data; + int ret; + + if (port >=3D smi->num_ports) + return -EINVAL; + + ret =3D regmap_read(smi->map, RTL8366RB_PORT_VLAN_CTRL_REG(port), + &data); + if (ret) + return ret; + + *val =3D (data >> RTL8366RB_PORT_VLAN_CTRL_SHIFT(port)) & + RTL8366RB_PORT_VLAN_CTRL_MASK; + + return 0; +} + +static int rtl8366rb_set_mc_index(struct realtek_smi *smi, int port, int i= ndex) +{ + struct rtl8366rb *rb; + bool pvid_enabled; + int ret; + + rb =3D smi->chip_data; + pvid_enabled =3D !!index; + + if (port >=3D smi->num_ports || index >=3D RTL8366RB_NUM_VLANS) + return -EINVAL; + + ret =3D regmap_update_bits(smi->map, RTL8366RB_PORT_VLAN_CTRL_REG(port), + RTL8366RB_PORT_VLAN_CTRL_MASK << + RTL8366RB_PORT_VLAN_CTRL_SHIFT(port), + (index & RTL8366RB_PORT_VLAN_CTRL_MASK) << + RTL8366RB_PORT_VLAN_CTRL_SHIFT(port)); + if (ret) + return ret; + + rb->pvid_enabled[port] =3D pvid_enabled; + + /* If VLAN filtering is enabled and PVID is also enabled, we must + * not drop any untagged or C-tagged frames. Make sure to update the + * filtering setting. + */ + if (dsa_port_is_vlan_filtering(dsa_to_port(smi->ds, port))) + ret =3D rtl8366rb_drop_untagged(smi, port, !pvid_enabled); + + return ret; +} + +static bool rtl8366rb_is_vlan_valid(struct realtek_smi *smi, unsigned int = vlan) +{ + unsigned int max =3D RTL8366RB_NUM_VLANS - 1; + + if (smi->vlan4k_enabled) + max =3D RTL8366RB_NUM_VIDS - 1; + + if (vlan > max) + return false; + + return true; +} + +static int rtl8366rb_enable_vlan(struct realtek_smi *smi, bool enable) +{ + dev_dbg(smi->dev, "%s VLAN\n", enable ? "enable" : "disable"); + return regmap_update_bits(smi->map, + RTL8366RB_SGCR, RTL8366RB_SGCR_EN_VLAN, + enable ? RTL8366RB_SGCR_EN_VLAN : 0); +} + +static int rtl8366rb_enable_vlan4k(struct realtek_smi *smi, bool enable) +{ + dev_dbg(smi->dev, "%s VLAN 4k\n", enable ? "enable" : "disable"); + return regmap_update_bits(smi->map, RTL8366RB_SGCR, + RTL8366RB_SGCR_EN_VLAN_4KTB, + enable ? RTL8366RB_SGCR_EN_VLAN_4KTB : 0); +} + +static int rtl8366rb_phy_read(struct realtek_smi *smi, int phy, int regnum) +{ + u32 val; + u32 reg; + int ret; + + if (phy > RTL8366RB_PHY_NO_MAX) + return -EINVAL; + + ret =3D regmap_write(smi->map, RTL8366RB_PHY_ACCESS_CTRL_REG, + RTL8366RB_PHY_CTRL_READ); + if (ret) + return ret; + + reg =3D 0x8000 | (1 << (phy + RTL8366RB_PHY_NO_OFFSET)) | regnum; + + ret =3D regmap_write(smi->map, reg, 0); + if (ret) { + dev_err(smi->dev, + "failed to write PHY%d reg %04x @ %04x, ret %d\n", + phy, regnum, reg, ret); + return ret; + } + + ret =3D regmap_read(smi->map, RTL8366RB_PHY_ACCESS_DATA_REG, &val); + if (ret) + return ret; + + dev_dbg(smi->dev, "read PHY%d register 0x%04x @ %08x, val <- %04x\n", + phy, regnum, reg, val); + + return val; +} + +static int rtl8366rb_phy_write(struct realtek_smi *smi, int phy, int regnu= m, + u16 val) +{ + u32 reg; + int ret; + + if (phy > RTL8366RB_PHY_NO_MAX) + return -EINVAL; + + ret =3D regmap_write(smi->map, RTL8366RB_PHY_ACCESS_CTRL_REG, + RTL8366RB_PHY_CTRL_WRITE); + if (ret) + return ret; + + reg =3D 0x8000 | (1 << (phy + RTL8366RB_PHY_NO_OFFSET)) | regnum; + + dev_dbg(smi->dev, "write PHY%d register 0x%04x @ %04x, val -> %04x\n", + phy, regnum, reg, val); + + ret =3D regmap_write(smi->map, reg, val); + if (ret) + return ret; + + return 0; +} + +static int rtl8366rb_reset_chip(struct realtek_smi *smi) +{ + int timeout =3D 10; + u32 val; + int ret; + + realtek_smi_write_reg_noack(smi, RTL8366RB_RESET_CTRL_REG, + RTL8366RB_CHIP_CTRL_RESET_HW); + do { + usleep_range(20000, 25000); + ret =3D regmap_read(smi->map, RTL8366RB_RESET_CTRL_REG, &val); + if (ret) + return ret; + + if (!(val & RTL8366RB_CHIP_CTRL_RESET_HW)) + break; + } while (--timeout); + + if (!timeout) { + dev_err(smi->dev, "timeout waiting for the switch to reset\n"); + return -EIO; + } + + return 0; +} + +static int rtl8366rb_detect(struct realtek_smi *smi) +{ + struct device *dev =3D smi->dev; + int ret; + u32 val; + + /* Detect device */ + ret =3D regmap_read(smi->map, 0x5c, &val); + if (ret) { + dev_err(dev, "can't get chip ID (%d)\n", ret); + return ret; + } + + switch (val) { + case 0x6027: + dev_info(dev, "found an RTL8366S switch\n"); + dev_err(dev, "this switch is not yet supported, submit patches!\n"); + return -ENODEV; + case 0x5937: + dev_info(dev, "found an RTL8366RB switch\n"); + smi->cpu_port =3D RTL8366RB_PORT_NUM_CPU; + smi->num_ports =3D RTL8366RB_NUM_PORTS; + smi->num_vlan_mc =3D RTL8366RB_NUM_VLANS; + smi->mib_counters =3D rtl8366rb_mib_counters; + smi->num_mib_counters =3D ARRAY_SIZE(rtl8366rb_mib_counters); + break; + default: + dev_info(dev, "found an Unknown Realtek switch (id=3D0x%04x)\n", + val); + break; + } + + ret =3D rtl8366rb_reset_chip(smi); + if (ret) + return ret; + + return 0; +} + +static const struct dsa_switch_ops rtl8366rb_switch_ops =3D { + .get_tag_protocol =3D rtl8366_get_tag_protocol, + .setup =3D rtl8366rb_setup, + .phylink_mac_link_up =3D rtl8366rb_mac_link_up, + .phylink_mac_link_down =3D rtl8366rb_mac_link_down, + .get_strings =3D rtl8366_get_strings, + .get_ethtool_stats =3D rtl8366_get_ethtool_stats, + .get_sset_count =3D rtl8366_get_sset_count, + .port_bridge_join =3D rtl8366rb_port_bridge_join, + .port_bridge_leave =3D rtl8366rb_port_bridge_leave, + .port_vlan_filtering =3D rtl8366rb_vlan_filtering, + .port_vlan_add =3D rtl8366_vlan_add, + .port_vlan_del =3D rtl8366_vlan_del, + .port_enable =3D rtl8366rb_port_enable, + .port_disable =3D rtl8366rb_port_disable, + .port_pre_bridge_flags =3D rtl8366rb_port_pre_bridge_flags, + .port_bridge_flags =3D rtl8366rb_port_bridge_flags, + .port_stp_state_set =3D rtl8366rb_port_stp_state_set, + .port_fast_age =3D rtl8366rb_port_fast_age, + .port_change_mtu =3D rtl8366rb_change_mtu, + .port_max_mtu =3D rtl8366rb_max_mtu, +}; + +static const struct realtek_smi_ops rtl8366rb_smi_ops =3D { + .detect =3D rtl8366rb_detect, + .get_vlan_mc =3D rtl8366rb_get_vlan_mc, + .set_vlan_mc =3D rtl8366rb_set_vlan_mc, + .get_vlan_4k =3D rtl8366rb_get_vlan_4k, + .set_vlan_4k =3D rtl8366rb_set_vlan_4k, + .get_mc_index =3D rtl8366rb_get_mc_index, + .set_mc_index =3D rtl8366rb_set_mc_index, + .get_mib_counter =3D rtl8366rb_get_mib_counter, + .is_vlan_valid =3D rtl8366rb_is_vlan_valid, + .enable_vlan =3D rtl8366rb_enable_vlan, + .enable_vlan4k =3D rtl8366rb_enable_vlan4k, + .phy_read =3D rtl8366rb_phy_read, + .phy_write =3D rtl8366rb_phy_write, +}; + +const struct realtek_smi_variant rtl8366rb_variant =3D { + .ds_ops =3D &rtl8366rb_switch_ops, + .ops =3D &rtl8366rb_smi_ops, + .clk_delay =3D 10, + .cmd_read =3D 0xa9, + .cmd_write =3D 0xa8, + .chip_data_sz =3D sizeof(struct rtl8366rb), +}; +EXPORT_SYMBOL_GPL(rtl8366rb_variant); diff --git a/drivers/net/dsa/rtl8365mb.c b/drivers/net/dsa/rtl8365mb.c deleted file mode 100644 index 48c0e3e46600..000000000000 --- a/drivers/net/dsa/rtl8365mb.c +++ /dev/null @@ -1,1986 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Realtek SMI subdriver for the Realtek RTL8365MB-VC ethernet switch. - * - * Copyright (C) 2021 Alvin =C5=A0ipraga - * Copyright (C) 2021 Michael Rasmussen - * - * The RTL8365MB-VC is a 4+1 port 10/100/1000M switch controller. It inclu= des 4 - * integrated PHYs for the user facing ports, and an extension interface w= hich - * can be connected to the CPU - or another PHY - via either MII, RMII, or - * RGMII. The switch is configured via the Realtek Simple Management Inter= face - * (SMI), which uses the MDIO/MDC lines. - * - * Below is a simplified block diagram of the chip and its relevant interf= aces. - * - * .-----------------------------------. - * | | - * UTP <---------------> Giga PHY <-> PCS <-> P0 GMAC | - * UTP <---------------> Giga PHY <-> PCS <-> P1 GMAC | - * UTP <---------------> Giga PHY <-> PCS <-> P2 GMAC | - * UTP <---------------> Giga PHY <-> PCS <-> P3 GMAC | - * | | - * CPU/PHY <-MII/RMII/RGMII---> Extension <---> Extension | - * | interface 1 GMAC 1 | - * | | - * SMI driver/ <-MDC/SCL---> Management ~~~~~~~~~~~~~~ | - * EEPROM <-MDIO/SDA--> interface ~REALTEK ~~~~~ | - * | ~RTL8365MB ~~~ | - * | ~GXXXC TAIWAN~ | - * GPIO <--------------> Reset ~~~~~~~~~~~~~~ | - * | | - * Interrupt <----------> Link UP/DOWN events | - * controller | | - * '-----------------------------------' - * - * The driver uses DSA to integrate the 4 user and 1 extension ports into = the - * kernel. Netdevices are created for the user ports, as are PHY devices f= or - * their integrated PHYs. The device tree firmware should also specify the= link - * partner of the extension port - either via a fixed-link or other phy-ha= ndle. - * See the device tree bindings for more detailed information. Note that t= he - * driver has only been tested with a fixed-link, but in principle it shou= ld not - * matter. - * - * NOTE: Currently, only the RGMII interface is implemented in this driver. - * - * The interrupt line is asserted on link UP/DOWN events. The driver creat= es a - * custom irqchip to handle this interrupt and demultiplex the events by r= eading - * the status registers via SMI. Interrupts are then propagated to the rel= evant - * PHY device. - * - * The EEPROM contains initial register values which the chip will read ov= er I2C - * upon hardware reset. It is also possible to omit the EEPROM. In both ca= ses, - * the driver will manually reprogram some registers using jam tables to r= each - * an initial state defined by the vendor driver. - * - * This Linux driver is written based on an OS-agnostic vendor driver from - * Realtek. The reference GPL-licensed sources can be found in the OpenWrt - * source tree under the name rtl8367c. The vendor driver claims to suppor= t a - * number of similar switch controllers from Realtek, but the only hardwar= e we - * have is the RTL8365MB-VC. Moreover, there does not seem to be any chip = under - * the name RTL8367C. Although one wishes that the 'C' stood for some kind= of - * common hardware revision, there exist examples of chips with the suffix= -VC - * which are explicitly not supported by the rtl8367c driver and which ins= tead - * require the rtl8367d vendor driver. With all this uncertainty, the driv= er has - * been modestly named rtl8365mb. Future implementors may wish to rename t= hings - * accordingly. - * - * In the same family of chips, some carry up to 8 user ports and up to 2 - * extension ports. Where possible this driver tries to make things generi= c, but - * more work must be done to support these configurations. According to - * documentation from Realtek, the family should include the following chi= ps: - * - * - RTL8363NB - * - RTL8363NB-VB - * - RTL8363SC - * - RTL8363SC-VB - * - RTL8364NB - * - RTL8364NB-VB - * - RTL8365MB-VC - * - RTL8366SC - * - RTL8367RB-VB - * - RTL8367SB - * - RTL8367S - * - RTL8370MB - * - RTL8310SR - * - * Some of the register logic for these additional chips has been skipped = over - * while implementing this driver. It is therefore not possible to assume = that - * things will work out-of-the-box for other chips, and a careful review o= f the - * vendor driver may be needed to expand support. The RTL8365MB-VC seems t= o be - * one of the simpler chips. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "realtek-smi-core.h" - -/* Chip-specific data and limits */ -#define RTL8365MB_CHIP_ID_8365MB_VC 0x6367 -#define RTL8365MB_CPU_PORT_NUM_8365MB_VC 6 -#define RTL8365MB_LEARN_LIMIT_MAX_8365MB_VC 2112 - -/* Family-specific data and limits */ -#define RTL8365MB_PHYADDRMAX 7 -#define RTL8365MB_NUM_PHYREGS 32 -#define RTL8365MB_PHYREGMAX (RTL8365MB_NUM_PHYREGS - 1) -#define RTL8365MB_MAX_NUM_PORTS (RTL8365MB_CPU_PORT_NUM_8365MB_VC + 1) - -/* Chip identification registers */ -#define RTL8365MB_CHIP_ID_REG 0x1300 - -#define RTL8365MB_CHIP_VER_REG 0x1301 - -#define RTL8365MB_MAGIC_REG 0x13C2 -#define RTL8365MB_MAGIC_VALUE 0x0249 - -/* Chip reset register */ -#define RTL8365MB_CHIP_RESET_REG 0x1322 -#define RTL8365MB_CHIP_RESET_SW_MASK 0x0002 -#define RTL8365MB_CHIP_RESET_HW_MASK 0x0001 - -/* Interrupt polarity register */ -#define RTL8365MB_INTR_POLARITY_REG 0x1100 -#define RTL8365MB_INTR_POLARITY_MASK 0x0001 -#define RTL8365MB_INTR_POLARITY_HIGH 0 -#define RTL8365MB_INTR_POLARITY_LOW 1 - -/* Interrupt control/status register - enable/check specific interrupt typ= es */ -#define RTL8365MB_INTR_CTRL_REG 0x1101 -#define RTL8365MB_INTR_STATUS_REG 0x1102 -#define RTL8365MB_INTR_SLIENT_START_2_MASK 0x1000 -#define RTL8365MB_INTR_SLIENT_START_MASK 0x0800 -#define RTL8365MB_INTR_ACL_ACTION_MASK 0x0200 -#define RTL8365MB_INTR_CABLE_DIAG_FIN_MASK 0x0100 -#define RTL8365MB_INTR_INTERRUPT_8051_MASK 0x0080 -#define RTL8365MB_INTR_LOOP_DETECTION_MASK 0x0040 -#define RTL8365MB_INTR_GREEN_TIMER_MASK 0x0020 -#define RTL8365MB_INTR_SPECIAL_CONGEST_MASK 0x0010 -#define RTL8365MB_INTR_SPEED_CHANGE_MASK 0x0008 -#define RTL8365MB_INTR_LEARN_OVER_MASK 0x0004 -#define RTL8365MB_INTR_METER_EXCEEDED_MASK 0x0002 -#define RTL8365MB_INTR_LINK_CHANGE_MASK 0x0001 -#define RTL8365MB_INTR_ALL_MASK \ - (RTL8365MB_INTR_SLIENT_START_2_MASK | \ - RTL8365MB_INTR_SLIENT_START_MASK | \ - RTL8365MB_INTR_ACL_ACTION_MASK | \ - RTL8365MB_INTR_CABLE_DIAG_FIN_MASK | \ - RTL8365MB_INTR_INTERRUPT_8051_MASK | \ - RTL8365MB_INTR_LOOP_DETECTION_MASK | \ - RTL8365MB_INTR_GREEN_TIMER_MASK | \ - RTL8365MB_INTR_SPECIAL_CONGEST_MASK | \ - RTL8365MB_INTR_SPEED_CHANGE_MASK | \ - RTL8365MB_INTR_LEARN_OVER_MASK | \ - RTL8365MB_INTR_METER_EXCEEDED_MASK | \ - RTL8365MB_INTR_LINK_CHANGE_MASK) - -/* Per-port interrupt type status registers */ -#define RTL8365MB_PORT_LINKDOWN_IND_REG 0x1106 -#define RTL8365MB_PORT_LINKDOWN_IND_MASK 0x07FF - -#define RTL8365MB_PORT_LINKUP_IND_REG 0x1107 -#define RTL8365MB_PORT_LINKUP_IND_MASK 0x07FF - -/* PHY indirect access registers */ -#define RTL8365MB_INDIRECT_ACCESS_CTRL_REG 0x1F00 -#define RTL8365MB_INDIRECT_ACCESS_CTRL_RW_MASK 0x0002 -#define RTL8365MB_INDIRECT_ACCESS_CTRL_RW_READ 0 -#define RTL8365MB_INDIRECT_ACCESS_CTRL_RW_WRITE 1 -#define RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_MASK 0x0001 -#define RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_VALUE 1 -#define RTL8365MB_INDIRECT_ACCESS_STATUS_REG 0x1F01 -#define RTL8365MB_INDIRECT_ACCESS_ADDRESS_REG 0x1F02 -#define RTL8365MB_INDIRECT_ACCESS_ADDRESS_OCPADR_5_1_MASK GENMASK(4, 0) -#define RTL8365MB_INDIRECT_ACCESS_ADDRESS_PHYNUM_MASK GENMASK(7, 5) -#define RTL8365MB_INDIRECT_ACCESS_ADDRESS_OCPADR_9_6_MASK GENMASK(11, 8) -#define RTL8365MB_PHY_BASE 0x2000 -#define RTL8365MB_INDIRECT_ACCESS_WRITE_DATA_REG 0x1F03 -#define RTL8365MB_INDIRECT_ACCESS_READ_DATA_REG 0x1F04 - -/* PHY OCP address prefix register */ -#define RTL8365MB_GPHY_OCP_MSB_0_REG 0x1D15 -#define RTL8365MB_GPHY_OCP_MSB_0_CFG_CPU_OCPADR_MASK 0x0FC0 -#define RTL8365MB_PHY_OCP_ADDR_PREFIX_MASK 0xFC00 - -/* The PHY OCP addresses of PHY registers 0~31 start here */ -#define RTL8365MB_PHY_OCP_ADDR_PHYREG_BASE 0xA400 - -/* EXT port interface mode values - used in DIGITAL_INTERFACE_SELECT */ -#define RTL8365MB_EXT_PORT_MODE_DISABLE 0 -#define RTL8365MB_EXT_PORT_MODE_RGMII 1 -#define RTL8365MB_EXT_PORT_MODE_MII_MAC 2 -#define RTL8365MB_EXT_PORT_MODE_MII_PHY 3 -#define RTL8365MB_EXT_PORT_MODE_TMII_MAC 4 -#define RTL8365MB_EXT_PORT_MODE_TMII_PHY 5 -#define RTL8365MB_EXT_PORT_MODE_GMII 6 -#define RTL8365MB_EXT_PORT_MODE_RMII_MAC 7 -#define RTL8365MB_EXT_PORT_MODE_RMII_PHY 8 -#define RTL8365MB_EXT_PORT_MODE_SGMII 9 -#define RTL8365MB_EXT_PORT_MODE_HSGMII 10 -#define RTL8365MB_EXT_PORT_MODE_1000X_100FX 11 -#define RTL8365MB_EXT_PORT_MODE_1000X 12 -#define RTL8365MB_EXT_PORT_MODE_100FX 13 - -/* EXT port interface mode configuration registers 0~1 */ -#define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG0 0x1305 -#define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1 0x13C3 -#define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG(_extport) \ - (RTL8365MB_DIGITAL_INTERFACE_SELECT_REG0 + \ - ((_extport) >> 1) * (0x13C3 - 0x1305)) -#define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(_extport) \ - (0xF << (((_extport) % 2))) -#define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET(_extport) \ - (((_extport) % 2) * 4) - -/* EXT port RGMII TX/RX delay configuration registers 1~2 */ -#define RTL8365MB_EXT_RGMXF_REG1 0x1307 -#define RTL8365MB_EXT_RGMXF_REG2 0x13C5 -#define RTL8365MB_EXT_RGMXF_REG(_extport) \ - (RTL8365MB_EXT_RGMXF_REG1 + \ - (((_extport) >> 1) * (0x13C5 - 0x1307))) -#define RTL8365MB_EXT_RGMXF_RXDELAY_MASK 0x0007 -#define RTL8365MB_EXT_RGMXF_TXDELAY_MASK 0x0008 - -/* External port speed values - used in DIGITAL_INTERFACE_FORCE */ -#define RTL8365MB_PORT_SPEED_10M 0 -#define RTL8365MB_PORT_SPEED_100M 1 -#define RTL8365MB_PORT_SPEED_1000M 2 - -/* EXT port force configuration registers 0~2 */ -#define RTL8365MB_DIGITAL_INTERFACE_FORCE_REG0 0x1310 -#define RTL8365MB_DIGITAL_INTERFACE_FORCE_REG1 0x1311 -#define RTL8365MB_DIGITAL_INTERFACE_FORCE_REG2 0x13C4 -#define RTL8365MB_DIGITAL_INTERFACE_FORCE_REG(_extport) \ - (RTL8365MB_DIGITAL_INTERFACE_FORCE_REG0 + \ - ((_extport) & 0x1) + \ - ((((_extport) >> 1) & 0x1) * (0x13C4 - 0x1310))) -#define RTL8365MB_DIGITAL_INTERFACE_FORCE_EN_MASK 0x1000 -#define RTL8365MB_DIGITAL_INTERFACE_FORCE_NWAY_MASK 0x0080 -#define RTL8365MB_DIGITAL_INTERFACE_FORCE_TXPAUSE_MASK 0x0040 -#define RTL8365MB_DIGITAL_INTERFACE_FORCE_RXPAUSE_MASK 0x0020 -#define RTL8365MB_DIGITAL_INTERFACE_FORCE_LINK_MASK 0x0010 -#define RTL8365MB_DIGITAL_INTERFACE_FORCE_DUPLEX_MASK 0x0004 -#define RTL8365MB_DIGITAL_INTERFACE_FORCE_SPEED_MASK 0x0003 - -/* CPU port mask register - controls which ports are treated as CPU ports = */ -#define RTL8365MB_CPU_PORT_MASK_REG 0x1219 -#define RTL8365MB_CPU_PORT_MASK_MASK 0x07FF - -/* CPU control register */ -#define RTL8365MB_CPU_CTRL_REG 0x121A -#define RTL8365MB_CPU_CTRL_TRAP_PORT_EXT_MASK 0x0400 -#define RTL8365MB_CPU_CTRL_TAG_FORMAT_MASK 0x0200 -#define RTL8365MB_CPU_CTRL_RXBYTECOUNT_MASK 0x0080 -#define RTL8365MB_CPU_CTRL_TAG_POSITION_MASK 0x0040 -#define RTL8365MB_CPU_CTRL_TRAP_PORT_MASK 0x0038 -#define RTL8365MB_CPU_CTRL_INSERTMODE_MASK 0x0006 -#define RTL8365MB_CPU_CTRL_EN_MASK 0x0001 - -/* Maximum packet length register */ -#define RTL8365MB_CFG0_MAX_LEN_REG 0x088C -#define RTL8365MB_CFG0_MAX_LEN_MASK 0x3FFF - -/* Port learning limit registers */ -#define RTL8365MB_LUT_PORT_LEARN_LIMIT_BASE 0x0A20 -#define RTL8365MB_LUT_PORT_LEARN_LIMIT_REG(_physport) \ - (RTL8365MB_LUT_PORT_LEARN_LIMIT_BASE + (_physport)) - -/* Port isolation (forwarding mask) registers */ -#define RTL8365MB_PORT_ISOLATION_REG_BASE 0x08A2 -#define RTL8365MB_PORT_ISOLATION_REG(_physport) \ - (RTL8365MB_PORT_ISOLATION_REG_BASE + (_physport)) -#define RTL8365MB_PORT_ISOLATION_MASK 0x07FF - -/* MSTP port state registers - indexed by tree instancrSTI (tree ine */ -#define RTL8365MB_MSTI_CTRL_BASE 0x0A00 -#define RTL8365MB_MSTI_CTRL_REG(_msti, _physport) \ - (RTL8365MB_MSTI_CTRL_BASE + ((_msti) << 1) + ((_physport) >> 3)) -#define RTL8365MB_MSTI_CTRL_PORT_STATE_OFFSET(_physport) ((_physport) <<= 1) -#define RTL8365MB_MSTI_CTRL_PORT_STATE_MASK(_physport) \ - (0x3 << RTL8365MB_MSTI_CTRL_PORT_STATE_OFFSET((_physport))) - -/* MIB counter value registers */ -#define RTL8365MB_MIB_COUNTER_BASE 0x1000 -#define RTL8365MB_MIB_COUNTER_REG(_x) (RTL8365MB_MIB_COUNTER_BASE + (_x)) - -/* MIB counter address register */ -#define RTL8365MB_MIB_ADDRESS_REG 0x1004 -#define RTL8365MB_MIB_ADDRESS_PORT_OFFSET 0x007C -#define RTL8365MB_MIB_ADDRESS(_p, _x) \ - (((RTL8365MB_MIB_ADDRESS_PORT_OFFSET) * (_p) + (_x)) >> 2) - -#define RTL8365MB_MIB_CTRL0_REG 0x1005 -#define RTL8365MB_MIB_CTRL0_RESET_MASK 0x0002 -#define RTL8365MB_MIB_CTRL0_BUSY_MASK 0x0001 - -/* The DSA callback .get_stats64 runs in atomic context, so we are not all= owed - * to block. On the other hand, accessing MIB counters absolutely requires= us to - * block. The solution is thus to schedule work which polls the MIB counte= rs - * asynchronously and updates some private data, which the callback can th= en - * fetch atomically. Three seconds should be a good enough polling interva= l. - */ -#define RTL8365MB_STATS_INTERVAL_JIFFIES (3 * HZ) - -enum rtl8365mb_mib_counter_index { - RTL8365MB_MIB_ifInOctets, - RTL8365MB_MIB_dot3StatsFCSErrors, - RTL8365MB_MIB_dot3StatsSymbolErrors, - RTL8365MB_MIB_dot3InPauseFrames, - RTL8365MB_MIB_dot3ControlInUnknownOpcodes, - RTL8365MB_MIB_etherStatsFragments, - RTL8365MB_MIB_etherStatsJabbers, - RTL8365MB_MIB_ifInUcastPkts, - RTL8365MB_MIB_etherStatsDropEvents, - RTL8365MB_MIB_ifInMulticastPkts, - RTL8365MB_MIB_ifInBroadcastPkts, - RTL8365MB_MIB_inMldChecksumError, - RTL8365MB_MIB_inIgmpChecksumError, - RTL8365MB_MIB_inMldSpecificQuery, - RTL8365MB_MIB_inMldGeneralQuery, - RTL8365MB_MIB_inIgmpSpecificQuery, - RTL8365MB_MIB_inIgmpGeneralQuery, - RTL8365MB_MIB_inMldLeaves, - RTL8365MB_MIB_inIgmpLeaves, - RTL8365MB_MIB_etherStatsOctets, - RTL8365MB_MIB_etherStatsUnderSizePkts, - RTL8365MB_MIB_etherOversizeStats, - RTL8365MB_MIB_etherStatsPkts64Octets, - RTL8365MB_MIB_etherStatsPkts65to127Octets, - RTL8365MB_MIB_etherStatsPkts128to255Octets, - RTL8365MB_MIB_etherStatsPkts256to511Octets, - RTL8365MB_MIB_etherStatsPkts512to1023Octets, - RTL8365MB_MIB_etherStatsPkts1024to1518Octets, - RTL8365MB_MIB_ifOutOctets, - RTL8365MB_MIB_dot3StatsSingleCollisionFrames, - RTL8365MB_MIB_dot3StatsMultipleCollisionFrames, - RTL8365MB_MIB_dot3StatsDeferredTransmissions, - RTL8365MB_MIB_dot3StatsLateCollisions, - RTL8365MB_MIB_etherStatsCollisions, - RTL8365MB_MIB_dot3StatsExcessiveCollisions, - RTL8365MB_MIB_dot3OutPauseFrames, - RTL8365MB_MIB_ifOutDiscards, - RTL8365MB_MIB_dot1dTpPortInDiscards, - RTL8365MB_MIB_ifOutUcastPkts, - RTL8365MB_MIB_ifOutMulticastPkts, - RTL8365MB_MIB_ifOutBroadcastPkts, - RTL8365MB_MIB_outOampduPkts, - RTL8365MB_MIB_inOampduPkts, - RTL8365MB_MIB_inIgmpJoinsSuccess, - RTL8365MB_MIB_inIgmpJoinsFail, - RTL8365MB_MIB_inMldJoinsSuccess, - RTL8365MB_MIB_inMldJoinsFail, - RTL8365MB_MIB_inReportSuppressionDrop, - RTL8365MB_MIB_inLeaveSuppressionDrop, - RTL8365MB_MIB_outIgmpReports, - RTL8365MB_MIB_outIgmpLeaves, - RTL8365MB_MIB_outIgmpGeneralQuery, - RTL8365MB_MIB_outIgmpSpecificQuery, - RTL8365MB_MIB_outMldReports, - RTL8365MB_MIB_outMldLeaves, - RTL8365MB_MIB_outMldGeneralQuery, - RTL8365MB_MIB_outMldSpecificQuery, - RTL8365MB_MIB_inKnownMulticastPkts, - RTL8365MB_MIB_END, -}; - -struct rtl8365mb_mib_counter { - u32 offset; - u32 length; - const char *name; -}; - -#define RTL8365MB_MAKE_MIB_COUNTER(_offset, _length, _name) \ - [RTL8365MB_MIB_ ## _name] =3D { _offset, _length, #_name } - -static struct rtl8365mb_mib_counter rtl8365mb_mib_counters[] =3D { - RTL8365MB_MAKE_MIB_COUNTER(0, 4, ifInOctets), - RTL8365MB_MAKE_MIB_COUNTER(4, 2, dot3StatsFCSErrors), - RTL8365MB_MAKE_MIB_COUNTER(6, 2, dot3StatsSymbolErrors), - RTL8365MB_MAKE_MIB_COUNTER(8, 2, dot3InPauseFrames), - RTL8365MB_MAKE_MIB_COUNTER(10, 2, dot3ControlInUnknownOpcodes), - RTL8365MB_MAKE_MIB_COUNTER(12, 2, etherStatsFragments), - RTL8365MB_MAKE_MIB_COUNTER(14, 2, etherStatsJabbers), - RTL8365MB_MAKE_MIB_COUNTER(16, 2, ifInUcastPkts), - RTL8365MB_MAKE_MIB_COUNTER(18, 2, etherStatsDropEvents), - RTL8365MB_MAKE_MIB_COUNTER(20, 2, ifInMulticastPkts), - RTL8365MB_MAKE_MIB_COUNTER(22, 2, ifInBroadcastPkts), - RTL8365MB_MAKE_MIB_COUNTER(24, 2, inMldChecksumError), - RTL8365MB_MAKE_MIB_COUNTER(26, 2, inIgmpChecksumError), - RTL8365MB_MAKE_MIB_COUNTER(28, 2, inMldSpecificQuery), - RTL8365MB_MAKE_MIB_COUNTER(30, 2, inMldGeneralQuery), - RTL8365MB_MAKE_MIB_COUNTER(32, 2, inIgmpSpecificQuery), - RTL8365MB_MAKE_MIB_COUNTER(34, 2, inIgmpGeneralQuery), - RTL8365MB_MAKE_MIB_COUNTER(36, 2, inMldLeaves), - RTL8365MB_MAKE_MIB_COUNTER(38, 2, inIgmpLeaves), - RTL8365MB_MAKE_MIB_COUNTER(40, 4, etherStatsOctets), - RTL8365MB_MAKE_MIB_COUNTER(44, 2, etherStatsUnderSizePkts), - RTL8365MB_MAKE_MIB_COUNTER(46, 2, etherOversizeStats), - RTL8365MB_MAKE_MIB_COUNTER(48, 2, etherStatsPkts64Octets), - RTL8365MB_MAKE_MIB_COUNTER(50, 2, etherStatsPkts65to127Octets), - RTL8365MB_MAKE_MIB_COUNTER(52, 2, etherStatsPkts128to255Octets), - RTL8365MB_MAKE_MIB_COUNTER(54, 2, etherStatsPkts256to511Octets), - RTL8365MB_MAKE_MIB_COUNTER(56, 2, etherStatsPkts512to1023Octets), - RTL8365MB_MAKE_MIB_COUNTER(58, 2, etherStatsPkts1024to1518Octets), - RTL8365MB_MAKE_MIB_COUNTER(60, 4, ifOutOctets), - RTL8365MB_MAKE_MIB_COUNTER(64, 2, dot3StatsSingleCollisionFrames), - RTL8365MB_MAKE_MIB_COUNTER(66, 2, dot3StatsMultipleCollisionFrames), - RTL8365MB_MAKE_MIB_COUNTER(68, 2, dot3StatsDeferredTransmissions), - RTL8365MB_MAKE_MIB_COUNTER(70, 2, dot3StatsLateCollisions), - RTL8365MB_MAKE_MIB_COUNTER(72, 2, etherStatsCollisions), - RTL8365MB_MAKE_MIB_COUNTER(74, 2, dot3StatsExcessiveCollisions), - RTL8365MB_MAKE_MIB_COUNTER(76, 2, dot3OutPauseFrames), - RTL8365MB_MAKE_MIB_COUNTER(78, 2, ifOutDiscards), - RTL8365MB_MAKE_MIB_COUNTER(80, 2, dot1dTpPortInDiscards), - RTL8365MB_MAKE_MIB_COUNTER(82, 2, ifOutUcastPkts), - RTL8365MB_MAKE_MIB_COUNTER(84, 2, ifOutMulticastPkts), - RTL8365MB_MAKE_MIB_COUNTER(86, 2, ifOutBroadcastPkts), - RTL8365MB_MAKE_MIB_COUNTER(88, 2, outOampduPkts), - RTL8365MB_MAKE_MIB_COUNTER(90, 2, inOampduPkts), - RTL8365MB_MAKE_MIB_COUNTER(92, 4, inIgmpJoinsSuccess), - RTL8365MB_MAKE_MIB_COUNTER(96, 2, inIgmpJoinsFail), - RTL8365MB_MAKE_MIB_COUNTER(98, 2, inMldJoinsSuccess), - RTL8365MB_MAKE_MIB_COUNTER(100, 2, inMldJoinsFail), - RTL8365MB_MAKE_MIB_COUNTER(102, 2, inReportSuppressionDrop), - RTL8365MB_MAKE_MIB_COUNTER(104, 2, inLeaveSuppressionDrop), - RTL8365MB_MAKE_MIB_COUNTER(106, 2, outIgmpReports), - RTL8365MB_MAKE_MIB_COUNTER(108, 2, outIgmpLeaves), - RTL8365MB_MAKE_MIB_COUNTER(110, 2, outIgmpGeneralQuery), - RTL8365MB_MAKE_MIB_COUNTER(112, 2, outIgmpSpecificQuery), - RTL8365MB_MAKE_MIB_COUNTER(114, 2, outMldReports), - RTL8365MB_MAKE_MIB_COUNTER(116, 2, outMldLeaves), - RTL8365MB_MAKE_MIB_COUNTER(118, 2, outMldGeneralQuery), - RTL8365MB_MAKE_MIB_COUNTER(120, 2, outMldSpecificQuery), - RTL8365MB_MAKE_MIB_COUNTER(122, 2, inKnownMulticastPkts), -}; - -static_assert(ARRAY_SIZE(rtl8365mb_mib_counters) =3D=3D RTL8365MB_MIB_END); - -struct rtl8365mb_jam_tbl_entry { - u16 reg; - u16 val; -}; - -/* Lifted from the vendor driver sources */ -static const struct rtl8365mb_jam_tbl_entry rtl8365mb_init_jam_8365mb_vc[]= =3D { - { 0x13EB, 0x15BB }, { 0x1303, 0x06D6 }, { 0x1304, 0x0700 }, - { 0x13E2, 0x003F }, { 0x13F9, 0x0090 }, { 0x121E, 0x03CA }, - { 0x1233, 0x0352 }, { 0x1237, 0x00A0 }, { 0x123A, 0x0030 }, - { 0x1239, 0x0084 }, { 0x0301, 0x1000 }, { 0x1349, 0x001F }, - { 0x18E0, 0x4004 }, { 0x122B, 0x241C }, { 0x1305, 0xC000 }, - { 0x13F0, 0x0000 }, -}; - -static const struct rtl8365mb_jam_tbl_entry rtl8365mb_init_jam_common[] = =3D { - { 0x1200, 0x7FCB }, { 0x0884, 0x0003 }, { 0x06EB, 0x0001 }, - { 0x03Fa, 0x0007 }, { 0x08C8, 0x00C0 }, { 0x0A30, 0x020E }, - { 0x0800, 0x0000 }, { 0x0802, 0x0000 }, { 0x09DA, 0x0013 }, - { 0x1D32, 0x0002 }, -}; - -enum rtl8365mb_stp_state { - RTL8365MB_STP_STATE_DISABLED =3D 0, - RTL8365MB_STP_STATE_BLOCKING =3D 1, - RTL8365MB_STP_STATE_LEARNING =3D 2, - RTL8365MB_STP_STATE_FORWARDING =3D 3, -}; - -enum rtl8365mb_cpu_insert { - RTL8365MB_CPU_INSERT_TO_ALL =3D 0, - RTL8365MB_CPU_INSERT_TO_TRAPPING =3D 1, - RTL8365MB_CPU_INSERT_TO_NONE =3D 2, -}; - -enum rtl8365mb_cpu_position { - RTL8365MB_CPU_POS_AFTER_SA =3D 0, - RTL8365MB_CPU_POS_BEFORE_CRC =3D 1, -}; - -enum rtl8365mb_cpu_format { - RTL8365MB_CPU_FORMAT_8BYTES =3D 0, - RTL8365MB_CPU_FORMAT_4BYTES =3D 1, -}; - -enum rtl8365mb_cpu_rxlen { - RTL8365MB_CPU_RXLEN_72BYTES =3D 0, - RTL8365MB_CPU_RXLEN_64BYTES =3D 1, -}; - -/** - * struct rtl8365mb_cpu - CPU port configuration - * @enable: enable/disable hardware insertion of CPU tag in switch->CPU fr= ames - * @mask: port mask of ports that parse should parse CPU tags - * @trap_port: forward trapped frames to this port - * @insert: CPU tag insertion mode in switch->CPU frames - * @position: position of CPU tag in frame - * @rx_length: minimum CPU RX length - * @format: CPU tag format - * - * Represents the CPU tagging and CPU port configuration of the switch. Th= ese - * settings are configurable at runtime. - */ -struct rtl8365mb_cpu { - bool enable; - u32 mask; - u32 trap_port; - enum rtl8365mb_cpu_insert insert; - enum rtl8365mb_cpu_position position; - enum rtl8365mb_cpu_rxlen rx_length; - enum rtl8365mb_cpu_format format; -}; - -/** - * struct rtl8365mb_port - private per-port data - * @smi: pointer to parent realtek_smi data - * @index: DSA port index, same as dsa_port::index - * @stats: link statistics populated by rtl8365mb_stats_poll, ready for at= omic - * access via rtl8365mb_get_stats64 - * @stats_lock: protect the stats structure during read/update - * @mib_work: delayed work for polling MIB counters - */ -struct rtl8365mb_port { - struct realtek_smi *smi; - unsigned int index; - struct rtnl_link_stats64 stats; - spinlock_t stats_lock; - struct delayed_work mib_work; -}; - -/** - * struct rtl8365mb - private chip-specific driver data - * @smi: pointer to parent realtek_smi data - * @irq: registered IRQ or zero - * @chip_id: chip identifier - * @chip_ver: chip silicon revision - * @port_mask: mask of all ports - * @learn_limit_max: maximum number of L2 addresses the chip can learn - * @cpu: CPU tagging and CPU port configuration for this chip - * @mib_lock: prevent concurrent reads of MIB counters - * @ports: per-port data - * @jam_table: chip-specific initialization jam table - * @jam_size: size of the chip's jam table - * - * Private data for this driver. - */ -struct rtl8365mb { - struct realtek_smi *smi; - int irq; - u32 chip_id; - u32 chip_ver; - u32 port_mask; - u32 learn_limit_max; - struct rtl8365mb_cpu cpu; - struct mutex mib_lock; - struct rtl8365mb_port ports[RTL8365MB_MAX_NUM_PORTS]; - const struct rtl8365mb_jam_tbl_entry *jam_table; - size_t jam_size; -}; - -static int rtl8365mb_phy_poll_busy(struct realtek_smi *smi) -{ - u32 val; - - return regmap_read_poll_timeout(smi->map, - RTL8365MB_INDIRECT_ACCESS_STATUS_REG, - val, !val, 10, 100); -} - -static int rtl8365mb_phy_ocp_prepare(struct realtek_smi *smi, int phy, - u32 ocp_addr) -{ - u32 val; - int ret; - - /* Set OCP prefix */ - val =3D FIELD_GET(RTL8365MB_PHY_OCP_ADDR_PREFIX_MASK, ocp_addr); - ret =3D regmap_update_bits( - smi->map, RTL8365MB_GPHY_OCP_MSB_0_REG, - RTL8365MB_GPHY_OCP_MSB_0_CFG_CPU_OCPADR_MASK, - FIELD_PREP(RTL8365MB_GPHY_OCP_MSB_0_CFG_CPU_OCPADR_MASK, val)); - if (ret) - return ret; - - /* Set PHY register address */ - val =3D RTL8365MB_PHY_BASE; - val |=3D FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_ADDRESS_PHYNUM_MASK, phy); - val |=3D FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_ADDRESS_OCPADR_5_1_MASK, - ocp_addr >> 1); - val |=3D FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_ADDRESS_OCPADR_9_6_MASK, - ocp_addr >> 6); - ret =3D regmap_write(smi->map, RTL8365MB_INDIRECT_ACCESS_ADDRESS_REG, - val); - if (ret) - return ret; - - return 0; -} - -static int rtl8365mb_phy_ocp_read(struct realtek_smi *smi, int phy, - u32 ocp_addr, u16 *data) -{ - u32 val; - int ret; - - ret =3D rtl8365mb_phy_poll_busy(smi); - if (ret) - return ret; - - ret =3D rtl8365mb_phy_ocp_prepare(smi, phy, ocp_addr); - if (ret) - return ret; - - /* Execute read operation */ - val =3D FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_MASK, - RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_VALUE) | - FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_RW_MASK, - RTL8365MB_INDIRECT_ACCESS_CTRL_RW_READ); - ret =3D regmap_write(smi->map, RTL8365MB_INDIRECT_ACCESS_CTRL_REG, val); - if (ret) - return ret; - - ret =3D rtl8365mb_phy_poll_busy(smi); - if (ret) - return ret; - - /* Get PHY register data */ - ret =3D regmap_read(smi->map, RTL8365MB_INDIRECT_ACCESS_READ_DATA_REG, - &val); - if (ret) - return ret; - - *data =3D val & 0xFFFF; - - return 0; -} - -static int rtl8365mb_phy_ocp_write(struct realtek_smi *smi, int phy, - u32 ocp_addr, u16 data) -{ - u32 val; - int ret; - - ret =3D rtl8365mb_phy_poll_busy(smi); - if (ret) - return ret; - - ret =3D rtl8365mb_phy_ocp_prepare(smi, phy, ocp_addr); - if (ret) - return ret; - - /* Set PHY register data */ - ret =3D regmap_write(smi->map, RTL8365MB_INDIRECT_ACCESS_WRITE_DATA_REG, - data); - if (ret) - return ret; - - /* Execute write operation */ - val =3D FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_MASK, - RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_VALUE) | - FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_RW_MASK, - RTL8365MB_INDIRECT_ACCESS_CTRL_RW_WRITE); - ret =3D regmap_write(smi->map, RTL8365MB_INDIRECT_ACCESS_CTRL_REG, val); - if (ret) - return ret; - - ret =3D rtl8365mb_phy_poll_busy(smi); - if (ret) - return ret; - - return 0; -} - -static int rtl8365mb_phy_read(struct realtek_smi *smi, int phy, int regnum) -{ - u32 ocp_addr; - u16 val; - int ret; - - if (phy > RTL8365MB_PHYADDRMAX) - return -EINVAL; - - if (regnum > RTL8365MB_PHYREGMAX) - return -EINVAL; - - ocp_addr =3D RTL8365MB_PHY_OCP_ADDR_PHYREG_BASE + regnum * 2; - - ret =3D rtl8365mb_phy_ocp_read(smi, phy, ocp_addr, &val); - if (ret) { - dev_err(smi->dev, - "failed to read PHY%d reg %02x @ %04x, ret %d\n", phy, - regnum, ocp_addr, ret); - return ret; - } - - dev_dbg(smi->dev, "read PHY%d register 0x%02x @ %04x, val <- %04x\n", - phy, regnum, ocp_addr, val); - - return val; -} - -static int rtl8365mb_phy_write(struct realtek_smi *smi, int phy, int regnu= m, - u16 val) -{ - u32 ocp_addr; - int ret; - - if (phy > RTL8365MB_PHYADDRMAX) - return -EINVAL; - - if (regnum > RTL8365MB_PHYREGMAX) - return -EINVAL; - - ocp_addr =3D RTL8365MB_PHY_OCP_ADDR_PHYREG_BASE + regnum * 2; - - ret =3D rtl8365mb_phy_ocp_write(smi, phy, ocp_addr, val); - if (ret) { - dev_err(smi->dev, - "failed to write PHY%d reg %02x @ %04x, ret %d\n", phy, - regnum, ocp_addr, ret); - return ret; - } - - dev_dbg(smi->dev, "write PHY%d register 0x%02x @ %04x, val -> %04x\n", - phy, regnum, ocp_addr, val); - - return 0; -} - -static enum dsa_tag_protocol -rtl8365mb_get_tag_protocol(struct dsa_switch *ds, int port, - enum dsa_tag_protocol mp) -{ - return DSA_TAG_PROTO_RTL8_4; -} - -static int rtl8365mb_ext_config_rgmii(struct realtek_smi *smi, int port, - phy_interface_t interface) -{ - struct device_node *dn; - struct dsa_port *dp; - int tx_delay =3D 0; - int rx_delay =3D 0; - int ext_port; - u32 val; - int ret; - - if (port =3D=3D smi->cpu_port) { - ext_port =3D 1; - } else { - dev_err(smi->dev, "only one EXT port is currently supported\n"); - return -EINVAL; - } - - dp =3D dsa_to_port(smi->ds, port); - dn =3D dp->dn; - - /* Set the RGMII TX/RX delay - * - * The Realtek vendor driver indicates the following possible - * configuration settings: - * - * TX delay: - * 0 =3D no delay, 1 =3D 2 ns delay - * RX delay: - * 0 =3D no delay, 7 =3D maximum delay - * Each step is approximately 0.3 ns, so the maximum delay is about - * 2.1 ns. - * - * The vendor driver also states that this must be configured *before* - * forcing the external interface into a particular mode, which is done - * in the rtl8365mb_phylink_mac_link_{up,down} functions. - * - * Only configure an RGMII TX (resp. RX) delay if the - * tx-internal-delay-ps (resp. rx-internal-delay-ps) OF property is - * specified. We ignore the detail of the RGMII interface mode - * (RGMII_{RXID, TXID, etc.}), as this is considered to be a PHY-only - * property. - */ - if (!of_property_read_u32(dn, "tx-internal-delay-ps", &val)) { - val =3D val / 1000; /* convert to ns */ - - if (val =3D=3D 0 || val =3D=3D 2) - tx_delay =3D val / 2; - else - dev_warn(smi->dev, - "EXT port TX delay must be 0 or 2 ns\n"); - } - - if (!of_property_read_u32(dn, "rx-internal-delay-ps", &val)) { - val =3D DIV_ROUND_CLOSEST(val, 300); /* convert to 0.3 ns step */ - - if (val <=3D 7) - rx_delay =3D val; - else - dev_warn(smi->dev, - "EXT port RX delay must be 0 to 2.1 ns\n"); - } - - ret =3D regmap_update_bits( - smi->map, RTL8365MB_EXT_RGMXF_REG(ext_port), - RTL8365MB_EXT_RGMXF_TXDELAY_MASK | - RTL8365MB_EXT_RGMXF_RXDELAY_MASK, - FIELD_PREP(RTL8365MB_EXT_RGMXF_TXDELAY_MASK, tx_delay) | - FIELD_PREP(RTL8365MB_EXT_RGMXF_RXDELAY_MASK, rx_delay)); - if (ret) - return ret; - - ret =3D regmap_update_bits( - smi->map, RTL8365MB_DIGITAL_INTERFACE_SELECT_REG(ext_port), - RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(ext_port), - RTL8365MB_EXT_PORT_MODE_RGMII - << RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET( - ext_port)); - if (ret) - return ret; - - return 0; -} - -static int rtl8365mb_ext_config_forcemode(struct realtek_smi *smi, int por= t, - bool link, int speed, int duplex, - bool tx_pause, bool rx_pause) -{ - u32 r_tx_pause; - u32 r_rx_pause; - u32 r_duplex; - u32 r_speed; - u32 r_link; - int ext_port; - int val; - int ret; - - if (port =3D=3D smi->cpu_port) { - ext_port =3D 1; - } else { - dev_err(smi->dev, "only one EXT port is currently supported\n"); - return -EINVAL; - } - - if (link) { - /* Force the link up with the desired configuration */ - r_link =3D 1; - r_rx_pause =3D rx_pause ? 1 : 0; - r_tx_pause =3D tx_pause ? 1 : 0; - - if (speed =3D=3D SPEED_1000) { - r_speed =3D RTL8365MB_PORT_SPEED_1000M; - } else if (speed =3D=3D SPEED_100) { - r_speed =3D RTL8365MB_PORT_SPEED_100M; - } else if (speed =3D=3D SPEED_10) { - r_speed =3D RTL8365MB_PORT_SPEED_10M; - } else { - dev_err(smi->dev, "unsupported port speed %s\n", - phy_speed_to_str(speed)); - return -EINVAL; - } - - if (duplex =3D=3D DUPLEX_FULL) { - r_duplex =3D 1; - } else if (duplex =3D=3D DUPLEX_HALF) { - r_duplex =3D 0; - } else { - dev_err(smi->dev, "unsupported duplex %s\n", - phy_duplex_to_str(duplex)); - return -EINVAL; - } - } else { - /* Force the link down and reset any programmed configuration */ - r_link =3D 0; - r_tx_pause =3D 0; - r_rx_pause =3D 0; - r_speed =3D 0; - r_duplex =3D 0; - } - - val =3D FIELD_PREP(RTL8365MB_DIGITAL_INTERFACE_FORCE_EN_MASK, 1) | - FIELD_PREP(RTL8365MB_DIGITAL_INTERFACE_FORCE_TXPAUSE_MASK, - r_tx_pause) | - FIELD_PREP(RTL8365MB_DIGITAL_INTERFACE_FORCE_RXPAUSE_MASK, - r_rx_pause) | - FIELD_PREP(RTL8365MB_DIGITAL_INTERFACE_FORCE_LINK_MASK, r_link) | - FIELD_PREP(RTL8365MB_DIGITAL_INTERFACE_FORCE_DUPLEX_MASK, - r_duplex) | - FIELD_PREP(RTL8365MB_DIGITAL_INTERFACE_FORCE_SPEED_MASK, r_speed); - ret =3D regmap_write(smi->map, - RTL8365MB_DIGITAL_INTERFACE_FORCE_REG(ext_port), - val); - if (ret) - return ret; - - return 0; -} - -static bool rtl8365mb_phy_mode_supported(struct dsa_switch *ds, int port, - phy_interface_t interface) -{ - if (dsa_is_user_port(ds, port) && - (interface =3D=3D PHY_INTERFACE_MODE_NA || - interface =3D=3D PHY_INTERFACE_MODE_INTERNAL)) - /* Internal PHY */ - return true; - else if (dsa_is_cpu_port(ds, port) && - phy_interface_mode_is_rgmii(interface)) - /* Extension MAC */ - return true; - - return false; -} - -static void rtl8365mb_phylink_validate(struct dsa_switch *ds, int port, - unsigned long *supported, - struct phylink_link_state *state) -{ - struct realtek_smi *smi =3D ds->priv; - __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) =3D { 0 }; - - /* include/linux/phylink.h says: - * When @state->interface is %PHY_INTERFACE_MODE_NA, phylink - * expects the MAC driver to return all supported link modes. - */ - if (state->interface !=3D PHY_INTERFACE_MODE_NA && - !rtl8365mb_phy_mode_supported(ds, port, state->interface)) { - dev_err(smi->dev, "phy mode %s is unsupported on port %d\n", - phy_modes(state->interface), port); - linkmode_zero(supported); - return; - } - - phylink_set_port_modes(mask); - - phylink_set(mask, Autoneg); - phylink_set(mask, Pause); - phylink_set(mask, Asym_Pause); - - phylink_set(mask, 10baseT_Half); - phylink_set(mask, 10baseT_Full); - phylink_set(mask, 100baseT_Half); - phylink_set(mask, 100baseT_Full); - phylink_set(mask, 1000baseT_Full); - - linkmode_and(supported, supported, mask); - linkmode_and(state->advertising, state->advertising, mask); -} - -static void rtl8365mb_phylink_mac_config(struct dsa_switch *ds, int port, - unsigned int mode, - const struct phylink_link_state *state) -{ - struct realtek_smi *smi =3D ds->priv; - int ret; - - if (!rtl8365mb_phy_mode_supported(ds, port, state->interface)) { - dev_err(smi->dev, "phy mode %s is unsupported on port %d\n", - phy_modes(state->interface), port); - return; - } - - if (mode !=3D MLO_AN_PHY && mode !=3D MLO_AN_FIXED) { - dev_err(smi->dev, - "port %d supports only conventional PHY or fixed-link\n", - port); - return; - } - - if (phy_interface_mode_is_rgmii(state->interface)) { - ret =3D rtl8365mb_ext_config_rgmii(smi, port, state->interface); - if (ret) - dev_err(smi->dev, - "failed to configure RGMII mode on port %d: %d\n", - port, ret); - return; - } - - /* TODO: Implement MII and RMII modes, which the RTL8365MB-VC also - * supports - */ -} - -static void rtl8365mb_phylink_mac_link_down(struct dsa_switch *ds, int por= t, - unsigned int mode, - phy_interface_t interface) -{ - struct realtek_smi *smi =3D ds->priv; - struct rtl8365mb_port *p; - struct rtl8365mb *mb; - int ret; - - mb =3D smi->chip_data; - p =3D &mb->ports[port]; - cancel_delayed_work_sync(&p->mib_work); - - if (phy_interface_mode_is_rgmii(interface)) { - ret =3D rtl8365mb_ext_config_forcemode(smi, port, false, 0, 0, - false, false); - if (ret) - dev_err(smi->dev, - "failed to reset forced mode on port %d: %d\n", - port, ret); - - return; - } -} - -static void rtl8365mb_phylink_mac_link_up(struct dsa_switch *ds, int port, - unsigned int mode, - phy_interface_t interface, - struct phy_device *phydev, int speed, - int duplex, bool tx_pause, - bool rx_pause) -{ - struct realtek_smi *smi =3D ds->priv; - struct rtl8365mb_port *p; - struct rtl8365mb *mb; - int ret; - - mb =3D smi->chip_data; - p =3D &mb->ports[port]; - schedule_delayed_work(&p->mib_work, 0); - - if (phy_interface_mode_is_rgmii(interface)) { - ret =3D rtl8365mb_ext_config_forcemode(smi, port, true, speed, - duplex, tx_pause, - rx_pause); - if (ret) - dev_err(smi->dev, - "failed to force mode on port %d: %d\n", port, - ret); - - return; - } -} - -static void rtl8365mb_port_stp_state_set(struct dsa_switch *ds, int port, - u8 state) -{ - struct realtek_smi *smi =3D ds->priv; - enum rtl8365mb_stp_state val; - int msti =3D 0; - - switch (state) { - case BR_STATE_DISABLED: - val =3D RTL8365MB_STP_STATE_DISABLED; - break; - case BR_STATE_BLOCKING: - case BR_STATE_LISTENING: - val =3D RTL8365MB_STP_STATE_BLOCKING; - break; - case BR_STATE_LEARNING: - val =3D RTL8365MB_STP_STATE_LEARNING; - break; - case BR_STATE_FORWARDING: - val =3D RTL8365MB_STP_STATE_FORWARDING; - break; - default: - dev_err(smi->dev, "invalid STP state: %u\n", state); - return; - } - - regmap_update_bits(smi->map, RTL8365MB_MSTI_CTRL_REG(msti, port), - RTL8365MB_MSTI_CTRL_PORT_STATE_MASK(port), - val << RTL8365MB_MSTI_CTRL_PORT_STATE_OFFSET(port)); -} - -static int rtl8365mb_port_set_learning(struct realtek_smi *smi, int port, - bool enable) -{ - struct rtl8365mb *mb =3D smi->chip_data; - - /* Enable/disable learning by limiting the number of L2 addresses the - * port can learn. Realtek documentation states that a limit of zero - * disables learning. When enabling learning, set it to the chip's - * maximum. - */ - return regmap_write(smi->map, RTL8365MB_LUT_PORT_LEARN_LIMIT_REG(port), - enable ? mb->learn_limit_max : 0); -} - -static int rtl8365mb_port_set_isolation(struct realtek_smi *smi, int port, - u32 mask) -{ - return regmap_write(smi->map, RTL8365MB_PORT_ISOLATION_REG(port), mask); -} - -static int rtl8365mb_mib_counter_read(struct realtek_smi *smi, int port, - u32 offset, u32 length, u64 *mibvalue) -{ - u64 tmpvalue =3D 0; - u32 val; - int ret; - int i; - - /* The MIB address is an SRAM address. We request a particular address - * and then poll the control register before reading the value from some - * counter registers. - */ - ret =3D regmap_write(smi->map, RTL8365MB_MIB_ADDRESS_REG, - RTL8365MB_MIB_ADDRESS(port, offset)); - if (ret) - return ret; - - /* Poll for completion */ - ret =3D regmap_read_poll_timeout(smi->map, RTL8365MB_MIB_CTRL0_REG, val, - !(val & RTL8365MB_MIB_CTRL0_BUSY_MASK), - 10, 100); - if (ret) - return ret; - - /* Presumably this indicates a MIB counter read failure */ - if (val & RTL8365MB_MIB_CTRL0_RESET_MASK) - return -EIO; - - /* There are four MIB counter registers each holding a 16 bit word of a - * MIB counter. Depending on the offset, we should read from the upper - * two or lower two registers. In case the MIB counter is 4 words, we - * read from all four registers. - */ - if (length =3D=3D 4) - offset =3D 3; - else - offset =3D (offset + 1) % 4; - - /* Read the MIB counter 16 bits at a time */ - for (i =3D 0; i < length; i++) { - ret =3D regmap_read(smi->map, - RTL8365MB_MIB_COUNTER_REG(offset - i), &val); - if (ret) - return ret; - - tmpvalue =3D ((tmpvalue) << 16) | (val & 0xFFFF); - } - - /* Only commit the result if no error occurred */ - *mibvalue =3D tmpvalue; - - return 0; -} - -static void rtl8365mb_get_ethtool_stats(struct dsa_switch *ds, int port, u= 64 *data) -{ - struct realtek_smi *smi =3D ds->priv; - struct rtl8365mb *mb; - int ret; - int i; - - mb =3D smi->chip_data; - - mutex_lock(&mb->mib_lock); - for (i =3D 0; i < RTL8365MB_MIB_END; i++) { - struct rtl8365mb_mib_counter *mib =3D &rtl8365mb_mib_counters[i]; - - ret =3D rtl8365mb_mib_counter_read(smi, port, mib->offset, - mib->length, &data[i]); - if (ret) { - dev_err(smi->dev, - "failed to read port %d counters: %d\n", port, - ret); - break; - } - } - mutex_unlock(&mb->mib_lock); -} - -static void rtl8365mb_get_strings(struct dsa_switch *ds, int port, u32 str= ingset, u8 *data) -{ - int i; - - if (stringset !=3D ETH_SS_STATS) - return; - - for (i =3D 0; i < RTL8365MB_MIB_END; i++) { - struct rtl8365mb_mib_counter *mib =3D &rtl8365mb_mib_counters[i]; - - strncpy(data + i * ETH_GSTRING_LEN, mib->name, ETH_GSTRING_LEN); - } -} - -static int rtl8365mb_get_sset_count(struct dsa_switch *ds, int port, int s= set) -{ - if (sset !=3D ETH_SS_STATS) - return -EOPNOTSUPP; - - return RTL8365MB_MIB_END; -} - -static void rtl8365mb_get_phy_stats(struct dsa_switch *ds, int port, - struct ethtool_eth_phy_stats *phy_stats) -{ - struct realtek_smi *smi =3D ds->priv; - struct rtl8365mb_mib_counter *mib; - struct rtl8365mb *mb; - - mb =3D smi->chip_data; - mib =3D &rtl8365mb_mib_counters[RTL8365MB_MIB_dot3StatsSymbolErrors]; - - mutex_lock(&mb->mib_lock); - rtl8365mb_mib_counter_read(smi, port, mib->offset, mib->length, - &phy_stats->SymbolErrorDuringCarrier); - mutex_unlock(&mb->mib_lock); -} - -static void rtl8365mb_get_mac_stats(struct dsa_switch *ds, int port, - struct ethtool_eth_mac_stats *mac_stats) -{ - u64 cnt[RTL8365MB_MIB_END] =3D { - [RTL8365MB_MIB_ifOutOctets] =3D 1, - [RTL8365MB_MIB_ifOutUcastPkts] =3D 1, - [RTL8365MB_MIB_ifOutMulticastPkts] =3D 1, - [RTL8365MB_MIB_ifOutBroadcastPkts] =3D 1, - [RTL8365MB_MIB_dot3OutPauseFrames] =3D 1, - [RTL8365MB_MIB_ifOutDiscards] =3D 1, - [RTL8365MB_MIB_ifInOctets] =3D 1, - [RTL8365MB_MIB_ifInUcastPkts] =3D 1, - [RTL8365MB_MIB_ifInMulticastPkts] =3D 1, - [RTL8365MB_MIB_ifInBroadcastPkts] =3D 1, - [RTL8365MB_MIB_dot3InPauseFrames] =3D 1, - [RTL8365MB_MIB_dot3StatsSingleCollisionFrames] =3D 1, - [RTL8365MB_MIB_dot3StatsMultipleCollisionFrames] =3D 1, - [RTL8365MB_MIB_dot3StatsFCSErrors] =3D 1, - [RTL8365MB_MIB_dot3StatsDeferredTransmissions] =3D 1, - [RTL8365MB_MIB_dot3StatsLateCollisions] =3D 1, - [RTL8365MB_MIB_dot3StatsExcessiveCollisions] =3D 1, - - }; - struct realtek_smi *smi =3D ds->priv; - struct rtl8365mb *mb; - int ret; - int i; - - mb =3D smi->chip_data; - - mutex_lock(&mb->mib_lock); - for (i =3D 0; i < RTL8365MB_MIB_END; i++) { - struct rtl8365mb_mib_counter *mib =3D &rtl8365mb_mib_counters[i]; - - /* Only fetch required MIB counters (marked =3D 1 above) */ - if (!cnt[i]) - continue; - - ret =3D rtl8365mb_mib_counter_read(smi, port, mib->offset, - mib->length, &cnt[i]); - if (ret) - break; - } - mutex_unlock(&mb->mib_lock); - - /* The RTL8365MB-VC exposes MIB objects, which we have to translate into - * IEEE 802.3 Managed Objects. This is not always completely faithful, - * but we try out best. See RFC 3635 for a detailed treatment of the - * subject. - */ - - mac_stats->FramesTransmittedOK =3D cnt[RTL8365MB_MIB_ifOutUcastPkts] + - cnt[RTL8365MB_MIB_ifOutMulticastPkts] + - cnt[RTL8365MB_MIB_ifOutBroadcastPkts] + - cnt[RTL8365MB_MIB_dot3OutPauseFrames] - - cnt[RTL8365MB_MIB_ifOutDiscards]; - mac_stats->SingleCollisionFrames =3D - cnt[RTL8365MB_MIB_dot3StatsSingleCollisionFrames]; - mac_stats->MultipleCollisionFrames =3D - cnt[RTL8365MB_MIB_dot3StatsMultipleCollisionFrames]; - mac_stats->FramesReceivedOK =3D cnt[RTL8365MB_MIB_ifInUcastPkts] + - cnt[RTL8365MB_MIB_ifInMulticastPkts] + - cnt[RTL8365MB_MIB_ifInBroadcastPkts] + - cnt[RTL8365MB_MIB_dot3InPauseFrames]; - mac_stats->FrameCheckSequenceErrors =3D - cnt[RTL8365MB_MIB_dot3StatsFCSErrors]; - mac_stats->OctetsTransmittedOK =3D cnt[RTL8365MB_MIB_ifOutOctets] - - 18 * mac_stats->FramesTransmittedOK; - mac_stats->FramesWithDeferredXmissions =3D - cnt[RTL8365MB_MIB_dot3StatsDeferredTransmissions]; - mac_stats->LateCollisions =3D cnt[RTL8365MB_MIB_dot3StatsLateCollisions]; - mac_stats->FramesAbortedDueToXSColls =3D - cnt[RTL8365MB_MIB_dot3StatsExcessiveCollisions]; - mac_stats->OctetsReceivedOK =3D cnt[RTL8365MB_MIB_ifInOctets] - - 18 * mac_stats->FramesReceivedOK; - mac_stats->MulticastFramesXmittedOK =3D - cnt[RTL8365MB_MIB_ifOutMulticastPkts]; - mac_stats->BroadcastFramesXmittedOK =3D - cnt[RTL8365MB_MIB_ifOutBroadcastPkts]; - mac_stats->MulticastFramesReceivedOK =3D - cnt[RTL8365MB_MIB_ifInMulticastPkts]; - mac_stats->BroadcastFramesReceivedOK =3D - cnt[RTL8365MB_MIB_ifInBroadcastPkts]; -} - -static void rtl8365mb_get_ctrl_stats(struct dsa_switch *ds, int port, - struct ethtool_eth_ctrl_stats *ctrl_stats) -{ - struct realtek_smi *smi =3D ds->priv; - struct rtl8365mb_mib_counter *mib; - struct rtl8365mb *mb; - - mb =3D smi->chip_data; - mib =3D &rtl8365mb_mib_counters[RTL8365MB_MIB_dot3ControlInUnknownOpcodes= ]; - - mutex_lock(&mb->mib_lock); - rtl8365mb_mib_counter_read(smi, port, mib->offset, mib->length, - &ctrl_stats->UnsupportedOpcodesReceived); - mutex_unlock(&mb->mib_lock); -} - -static void rtl8365mb_stats_update(struct realtek_smi *smi, int port) -{ - u64 cnt[RTL8365MB_MIB_END] =3D { - [RTL8365MB_MIB_ifOutOctets] =3D 1, - [RTL8365MB_MIB_ifOutUcastPkts] =3D 1, - [RTL8365MB_MIB_ifOutMulticastPkts] =3D 1, - [RTL8365MB_MIB_ifOutBroadcastPkts] =3D 1, - [RTL8365MB_MIB_ifOutDiscards] =3D 1, - [RTL8365MB_MIB_ifInOctets] =3D 1, - [RTL8365MB_MIB_ifInUcastPkts] =3D 1, - [RTL8365MB_MIB_ifInMulticastPkts] =3D 1, - [RTL8365MB_MIB_ifInBroadcastPkts] =3D 1, - [RTL8365MB_MIB_etherStatsDropEvents] =3D 1, - [RTL8365MB_MIB_etherStatsCollisions] =3D 1, - [RTL8365MB_MIB_etherStatsFragments] =3D 1, - [RTL8365MB_MIB_etherStatsJabbers] =3D 1, - [RTL8365MB_MIB_dot3StatsFCSErrors] =3D 1, - [RTL8365MB_MIB_dot3StatsLateCollisions] =3D 1, - }; - struct rtl8365mb *mb =3D smi->chip_data; - struct rtnl_link_stats64 *stats; - int ret; - int i; - - stats =3D &mb->ports[port].stats; - - mutex_lock(&mb->mib_lock); - for (i =3D 0; i < RTL8365MB_MIB_END; i++) { - struct rtl8365mb_mib_counter *c =3D &rtl8365mb_mib_counters[i]; - - /* Only fetch required MIB counters (marked =3D 1 above) */ - if (!cnt[i]) - continue; - - ret =3D rtl8365mb_mib_counter_read(smi, port, c->offset, - c->length, &cnt[i]); - if (ret) - break; - } - mutex_unlock(&mb->mib_lock); - - /* Don't update statistics if there was an error reading the counters */ - if (ret) - return; - - spin_lock(&mb->ports[port].stats_lock); - - stats->rx_packets =3D cnt[RTL8365MB_MIB_ifInUcastPkts] + - cnt[RTL8365MB_MIB_ifInMulticastPkts] + - cnt[RTL8365MB_MIB_ifInBroadcastPkts] - - cnt[RTL8365MB_MIB_ifOutDiscards]; - - stats->tx_packets =3D cnt[RTL8365MB_MIB_ifOutUcastPkts] + - cnt[RTL8365MB_MIB_ifOutMulticastPkts] + - cnt[RTL8365MB_MIB_ifOutBroadcastPkts]; - - /* if{In,Out}Octets includes FCS - remove it */ - stats->rx_bytes =3D cnt[RTL8365MB_MIB_ifInOctets] - 4 * stats->rx_packets; - stats->tx_bytes =3D - cnt[RTL8365MB_MIB_ifOutOctets] - 4 * stats->tx_packets; - - stats->rx_dropped =3D cnt[RTL8365MB_MIB_etherStatsDropEvents]; - stats->tx_dropped =3D cnt[RTL8365MB_MIB_ifOutDiscards]; - - stats->multicast =3D cnt[RTL8365MB_MIB_ifInMulticastPkts]; - stats->collisions =3D cnt[RTL8365MB_MIB_etherStatsCollisions]; - - stats->rx_length_errors =3D cnt[RTL8365MB_MIB_etherStatsFragments] + - cnt[RTL8365MB_MIB_etherStatsJabbers]; - stats->rx_crc_errors =3D cnt[RTL8365MB_MIB_dot3StatsFCSErrors]; - stats->rx_errors =3D stats->rx_length_errors + stats->rx_crc_errors; - - stats->tx_aborted_errors =3D cnt[RTL8365MB_MIB_ifOutDiscards]; - stats->tx_window_errors =3D cnt[RTL8365MB_MIB_dot3StatsLateCollisions]; - stats->tx_errors =3D stats->tx_aborted_errors + stats->tx_window_errors; - - spin_unlock(&mb->ports[port].stats_lock); -} - -static void rtl8365mb_stats_poll(struct work_struct *work) -{ - struct rtl8365mb_port *p =3D container_of(to_delayed_work(work), - struct rtl8365mb_port, - mib_work); - struct realtek_smi *smi =3D p->smi; - - rtl8365mb_stats_update(smi, p->index); - - schedule_delayed_work(&p->mib_work, RTL8365MB_STATS_INTERVAL_JIFFIES); -} - -static void rtl8365mb_get_stats64(struct dsa_switch *ds, int port, - struct rtnl_link_stats64 *s) -{ - struct realtek_smi *smi =3D ds->priv; - struct rtl8365mb_port *p; - struct rtl8365mb *mb; - - mb =3D smi->chip_data; - p =3D &mb->ports[port]; - - spin_lock(&p->stats_lock); - memcpy(s, &p->stats, sizeof(*s)); - spin_unlock(&p->stats_lock); -} - -static void rtl8365mb_stats_setup(struct realtek_smi *smi) -{ - struct rtl8365mb *mb =3D smi->chip_data; - int i; - - /* Per-chip global mutex to protect MIB counter access, since doing - * so requires accessing a series of registers in a particular order. - */ - mutex_init(&mb->mib_lock); - - for (i =3D 0; i < smi->num_ports; i++) { - struct rtl8365mb_port *p =3D &mb->ports[i]; - - if (dsa_is_unused_port(smi->ds, i)) - continue; - - /* Per-port spinlock to protect the stats64 data */ - spin_lock_init(&p->stats_lock); - - /* This work polls the MIB counters and keeps the stats64 data - * up-to-date. - */ - INIT_DELAYED_WORK(&p->mib_work, rtl8365mb_stats_poll); - } -} - -static void rtl8365mb_stats_teardown(struct realtek_smi *smi) -{ - struct rtl8365mb *mb =3D smi->chip_data; - int i; - - for (i =3D 0; i < smi->num_ports; i++) { - struct rtl8365mb_port *p =3D &mb->ports[i]; - - if (dsa_is_unused_port(smi->ds, i)) - continue; - - cancel_delayed_work_sync(&p->mib_work); - } -} - -static int rtl8365mb_get_and_clear_status_reg(struct realtek_smi *smi, u32= reg, - u32 *val) -{ - int ret; - - ret =3D regmap_read(smi->map, reg, val); - if (ret) - return ret; - - return regmap_write(smi->map, reg, *val); -} - -static irqreturn_t rtl8365mb_irq(int irq, void *data) -{ - struct realtek_smi *smi =3D data; - unsigned long line_changes =3D 0; - struct rtl8365mb *mb; - u32 stat; - int line; - int ret; - - mb =3D smi->chip_data; - - ret =3D rtl8365mb_get_and_clear_status_reg(smi, RTL8365MB_INTR_STATUS_REG, - &stat); - if (ret) - goto out_error; - - if (stat & RTL8365MB_INTR_LINK_CHANGE_MASK) { - u32 linkdown_ind; - u32 linkup_ind; - u32 val; - - ret =3D rtl8365mb_get_and_clear_status_reg( - smi, RTL8365MB_PORT_LINKUP_IND_REG, &val); - if (ret) - goto out_error; - - linkup_ind =3D FIELD_GET(RTL8365MB_PORT_LINKUP_IND_MASK, val); - - ret =3D rtl8365mb_get_and_clear_status_reg( - smi, RTL8365MB_PORT_LINKDOWN_IND_REG, &val); - if (ret) - goto out_error; - - linkdown_ind =3D FIELD_GET(RTL8365MB_PORT_LINKDOWN_IND_MASK, val); - - line_changes =3D (linkup_ind | linkdown_ind) & mb->port_mask; - } - - if (!line_changes) - goto out_none; - - for_each_set_bit(line, &line_changes, smi->num_ports) { - int child_irq =3D irq_find_mapping(smi->irqdomain, line); - - handle_nested_irq(child_irq); - } - - return IRQ_HANDLED; - -out_error: - dev_err(smi->dev, "failed to read interrupt status: %d\n", ret); - -out_none: - return IRQ_NONE; -} - -static struct irq_chip rtl8365mb_irq_chip =3D { - .name =3D "rtl8365mb", - /* The hardware doesn't support masking IRQs on a per-port basis */ -}; - -static int rtl8365mb_irq_map(struct irq_domain *domain, unsigned int irq, - irq_hw_number_t hwirq) -{ - irq_set_chip_data(irq, domain->host_data); - irq_set_chip_and_handler(irq, &rtl8365mb_irq_chip, handle_simple_irq); - irq_set_nested_thread(irq, 1); - irq_set_noprobe(irq); - - return 0; -} - -static void rtl8365mb_irq_unmap(struct irq_domain *d, unsigned int irq) -{ - irq_set_nested_thread(irq, 0); - irq_set_chip_and_handler(irq, NULL, NULL); - irq_set_chip_data(irq, NULL); -} - -static const struct irq_domain_ops rtl8365mb_irqdomain_ops =3D { - .map =3D rtl8365mb_irq_map, - .unmap =3D rtl8365mb_irq_unmap, - .xlate =3D irq_domain_xlate_onecell, -}; - -static int rtl8365mb_set_irq_enable(struct realtek_smi *smi, bool enable) -{ - return regmap_update_bits(smi->map, RTL8365MB_INTR_CTRL_REG, - RTL8365MB_INTR_LINK_CHANGE_MASK, - FIELD_PREP(RTL8365MB_INTR_LINK_CHANGE_MASK, - enable ? 1 : 0)); -} - -static int rtl8365mb_irq_enable(struct realtek_smi *smi) -{ - return rtl8365mb_set_irq_enable(smi, true); -} - -static int rtl8365mb_irq_disable(struct realtek_smi *smi) -{ - return rtl8365mb_set_irq_enable(smi, false); -} - -static int rtl8365mb_irq_setup(struct realtek_smi *smi) -{ - struct rtl8365mb *mb =3D smi->chip_data; - struct device_node *intc; - u32 irq_trig; - int virq; - int irq; - u32 val; - int ret; - int i; - - intc =3D of_get_child_by_name(smi->dev->of_node, "interrupt-controller"); - if (!intc) { - dev_err(smi->dev, "missing child interrupt-controller node\n"); - return -EINVAL; - } - - /* rtl8365mb IRQs cascade off this one */ - irq =3D of_irq_get(intc, 0); - if (irq <=3D 0) { - if (irq !=3D -EPROBE_DEFER) - dev_err(smi->dev, "failed to get parent irq: %d\n", - irq); - ret =3D irq ? irq : -EINVAL; - goto out_put_node; - } - - smi->irqdomain =3D irq_domain_add_linear(intc, smi->num_ports, - &rtl8365mb_irqdomain_ops, smi); - if (!smi->irqdomain) { - dev_err(smi->dev, "failed to add irq domain\n"); - ret =3D -ENOMEM; - goto out_put_node; - } - - for (i =3D 0; i < smi->num_ports; i++) { - virq =3D irq_create_mapping(smi->irqdomain, i); - if (!virq) { - dev_err(smi->dev, - "failed to create irq domain mapping\n"); - ret =3D -EINVAL; - goto out_remove_irqdomain; - } - - irq_set_parent(virq, irq); - } - - /* Configure chip interrupt signal polarity */ - irq_trig =3D irqd_get_trigger_type(irq_get_irq_data(irq)); - switch (irq_trig) { - case IRQF_TRIGGER_RISING: - case IRQF_TRIGGER_HIGH: - val =3D RTL8365MB_INTR_POLARITY_HIGH; - break; - case IRQF_TRIGGER_FALLING: - case IRQF_TRIGGER_LOW: - val =3D RTL8365MB_INTR_POLARITY_LOW; - break; - default: - dev_err(smi->dev, "unsupported irq trigger type %u\n", - irq_trig); - ret =3D -EINVAL; - goto out_remove_irqdomain; - } - - ret =3D regmap_update_bits(smi->map, RTL8365MB_INTR_POLARITY_REG, - RTL8365MB_INTR_POLARITY_MASK, - FIELD_PREP(RTL8365MB_INTR_POLARITY_MASK, val)); - if (ret) - goto out_remove_irqdomain; - - /* Disable the interrupt in case the chip has it enabled on reset */ - ret =3D rtl8365mb_irq_disable(smi); - if (ret) - goto out_remove_irqdomain; - - /* Clear the interrupt status register */ - ret =3D regmap_write(smi->map, RTL8365MB_INTR_STATUS_REG, - RTL8365MB_INTR_ALL_MASK); - if (ret) - goto out_remove_irqdomain; - - ret =3D request_threaded_irq(irq, NULL, rtl8365mb_irq, IRQF_ONESHOT, - "rtl8365mb", smi); - if (ret) { - dev_err(smi->dev, "failed to request irq: %d\n", ret); - goto out_remove_irqdomain; - } - - /* Store the irq so that we know to free it during teardown */ - mb->irq =3D irq; - - ret =3D rtl8365mb_irq_enable(smi); - if (ret) - goto out_free_irq; - - of_node_put(intc); - - return 0; - -out_free_irq: - free_irq(mb->irq, smi); - mb->irq =3D 0; - -out_remove_irqdomain: - for (i =3D 0; i < smi->num_ports; i++) { - virq =3D irq_find_mapping(smi->irqdomain, i); - irq_dispose_mapping(virq); - } - - irq_domain_remove(smi->irqdomain); - smi->irqdomain =3D NULL; - -out_put_node: - of_node_put(intc); - - return ret; -} - -static void rtl8365mb_irq_teardown(struct realtek_smi *smi) -{ - struct rtl8365mb *mb =3D smi->chip_data; - int virq; - int i; - - if (mb->irq) { - free_irq(mb->irq, smi); - mb->irq =3D 0; - } - - if (smi->irqdomain) { - for (i =3D 0; i < smi->num_ports; i++) { - virq =3D irq_find_mapping(smi->irqdomain, i); - irq_dispose_mapping(virq); - } - - irq_domain_remove(smi->irqdomain); - smi->irqdomain =3D NULL; - } -} - -static int rtl8365mb_cpu_config(struct realtek_smi *smi) -{ - struct rtl8365mb *mb =3D smi->chip_data; - struct rtl8365mb_cpu *cpu =3D &mb->cpu; - u32 val; - int ret; - - ret =3D regmap_update_bits(smi->map, RTL8365MB_CPU_PORT_MASK_REG, - RTL8365MB_CPU_PORT_MASK_MASK, - FIELD_PREP(RTL8365MB_CPU_PORT_MASK_MASK, - cpu->mask)); - if (ret) - return ret; - - val =3D FIELD_PREP(RTL8365MB_CPU_CTRL_EN_MASK, cpu->enable ? 1 : 0) | - FIELD_PREP(RTL8365MB_CPU_CTRL_INSERTMODE_MASK, cpu->insert) | - FIELD_PREP(RTL8365MB_CPU_CTRL_TAG_POSITION_MASK, cpu->position) | - FIELD_PREP(RTL8365MB_CPU_CTRL_RXBYTECOUNT_MASK, cpu->rx_length) | - FIELD_PREP(RTL8365MB_CPU_CTRL_TAG_FORMAT_MASK, cpu->format) | - FIELD_PREP(RTL8365MB_CPU_CTRL_TRAP_PORT_MASK, cpu->trap_port) | - FIELD_PREP(RTL8365MB_CPU_CTRL_TRAP_PORT_EXT_MASK, - cpu->trap_port >> 3); - ret =3D regmap_write(smi->map, RTL8365MB_CPU_CTRL_REG, val); - if (ret) - return ret; - - return 0; -} - -static int rtl8365mb_switch_init(struct realtek_smi *smi) -{ - struct rtl8365mb *mb =3D smi->chip_data; - int ret; - int i; - - /* Do any chip-specific init jam before getting to the common stuff */ - if (mb->jam_table) { - for (i =3D 0; i < mb->jam_size; i++) { - ret =3D regmap_write(smi->map, mb->jam_table[i].reg, - mb->jam_table[i].val); - if (ret) - return ret; - } - } - - /* Common init jam */ - for (i =3D 0; i < ARRAY_SIZE(rtl8365mb_init_jam_common); i++) { - ret =3D regmap_write(smi->map, rtl8365mb_init_jam_common[i].reg, - rtl8365mb_init_jam_common[i].val); - if (ret) - return ret; - } - - return 0; -} - -static int rtl8365mb_reset_chip(struct realtek_smi *smi) -{ - u32 val; - - realtek_smi_write_reg_noack(smi, RTL8365MB_CHIP_RESET_REG, - FIELD_PREP(RTL8365MB_CHIP_RESET_HW_MASK, - 1)); - - /* Realtek documentation says the chip needs 1 second to reset. Sleep - * for 100 ms before accessing any registers to prevent ACK timeouts. - */ - msleep(100); - return regmap_read_poll_timeout(smi->map, RTL8365MB_CHIP_RESET_REG, val, - !(val & RTL8365MB_CHIP_RESET_HW_MASK), - 20000, 1e6); -} - -static int rtl8365mb_setup(struct dsa_switch *ds) -{ - struct realtek_smi *smi =3D ds->priv; - struct rtl8365mb *mb; - int ret; - int i; - - mb =3D smi->chip_data; - - ret =3D rtl8365mb_reset_chip(smi); - if (ret) { - dev_err(smi->dev, "failed to reset chip: %d\n", ret); - goto out_error; - } - - /* Configure switch to vendor-defined initial state */ - ret =3D rtl8365mb_switch_init(smi); - if (ret) { - dev_err(smi->dev, "failed to initialize switch: %d\n", ret); - goto out_error; - } - - /* Set up cascading IRQs */ - ret =3D rtl8365mb_irq_setup(smi); - if (ret =3D=3D -EPROBE_DEFER) - return ret; - else if (ret) - dev_info(smi->dev, "no interrupt support\n"); - - /* Configure CPU tagging */ - ret =3D rtl8365mb_cpu_config(smi); - if (ret) - goto out_teardown_irq; - - /* Configure ports */ - for (i =3D 0; i < smi->num_ports; i++) { - struct rtl8365mb_port *p =3D &mb->ports[i]; - - if (dsa_is_unused_port(smi->ds, i)) - continue; - - /* Set up per-port private data */ - p->smi =3D smi; - p->index =3D i; - - /* Forward only to the CPU */ - ret =3D rtl8365mb_port_set_isolation(smi, i, BIT(smi->cpu_port)); - if (ret) - goto out_teardown_irq; - - /* Disable learning */ - ret =3D rtl8365mb_port_set_learning(smi, i, false); - if (ret) - goto out_teardown_irq; - - /* Set the initial STP state of all ports to DISABLED, otherwise - * ports will still forward frames to the CPU despite being - * administratively down by default. - */ - rtl8365mb_port_stp_state_set(smi->ds, i, BR_STATE_DISABLED); - } - - /* Set maximum packet length to 1536 bytes */ - ret =3D regmap_update_bits(smi->map, RTL8365MB_CFG0_MAX_LEN_REG, - RTL8365MB_CFG0_MAX_LEN_MASK, - FIELD_PREP(RTL8365MB_CFG0_MAX_LEN_MASK, 1536)); - if (ret) - goto out_teardown_irq; - - ret =3D realtek_smi_setup_mdio(smi); - if (ret) { - dev_err(smi->dev, "could not set up MDIO bus\n"); - goto out_teardown_irq; - } - - /* Start statistics counter polling */ - rtl8365mb_stats_setup(smi); - - return 0; - -out_teardown_irq: - rtl8365mb_irq_teardown(smi); - -out_error: - return ret; -} - -static void rtl8365mb_teardown(struct dsa_switch *ds) -{ - struct realtek_smi *smi =3D ds->priv; - - rtl8365mb_stats_teardown(smi); - rtl8365mb_irq_teardown(smi); -} - -static int rtl8365mb_get_chip_id_and_ver(struct regmap *map, u32 *id, u32 = *ver) -{ - int ret; - - /* For some reason we have to write a magic value to an arbitrary - * register whenever accessing the chip ID/version registers. - */ - ret =3D regmap_write(map, RTL8365MB_MAGIC_REG, RTL8365MB_MAGIC_VALUE); - if (ret) - return ret; - - ret =3D regmap_read(map, RTL8365MB_CHIP_ID_REG, id); - if (ret) - return ret; - - ret =3D regmap_read(map, RTL8365MB_CHIP_VER_REG, ver); - if (ret) - return ret; - - /* Reset magic register */ - ret =3D regmap_write(map, RTL8365MB_MAGIC_REG, 0); - if (ret) - return ret; - - return 0; -} - -static int rtl8365mb_detect(struct realtek_smi *smi) -{ - struct rtl8365mb *mb =3D smi->chip_data; - u32 chip_id; - u32 chip_ver; - int ret; - - ret =3D rtl8365mb_get_chip_id_and_ver(smi->map, &chip_id, &chip_ver); - if (ret) { - dev_err(smi->dev, "failed to read chip id and version: %d\n", - ret); - return ret; - } - - switch (chip_id) { - case RTL8365MB_CHIP_ID_8365MB_VC: - dev_info(smi->dev, - "found an RTL8365MB-VC switch (ver=3D0x%04x)\n", - chip_ver); - - smi->cpu_port =3D RTL8365MB_CPU_PORT_NUM_8365MB_VC; - smi->num_ports =3D smi->cpu_port + 1; - - mb->smi =3D smi; - mb->chip_id =3D chip_id; - mb->chip_ver =3D chip_ver; - mb->port_mask =3D BIT(smi->num_ports) - 1; - mb->learn_limit_max =3D RTL8365MB_LEARN_LIMIT_MAX_8365MB_VC; - mb->jam_table =3D rtl8365mb_init_jam_8365mb_vc; - mb->jam_size =3D ARRAY_SIZE(rtl8365mb_init_jam_8365mb_vc); - - mb->cpu.enable =3D 1; - mb->cpu.mask =3D BIT(smi->cpu_port); - mb->cpu.trap_port =3D smi->cpu_port; - mb->cpu.insert =3D RTL8365MB_CPU_INSERT_TO_ALL; - mb->cpu.position =3D RTL8365MB_CPU_POS_AFTER_SA; - mb->cpu.rx_length =3D RTL8365MB_CPU_RXLEN_64BYTES; - mb->cpu.format =3D RTL8365MB_CPU_FORMAT_8BYTES; - - break; - default: - dev_err(smi->dev, - "found an unknown Realtek switch (id=3D0x%04x, ver=3D0x%04x)\n", - chip_id, chip_ver); - return -ENODEV; - } - - return 0; -} - -static const struct dsa_switch_ops rtl8365mb_switch_ops =3D { - .get_tag_protocol =3D rtl8365mb_get_tag_protocol, - .setup =3D rtl8365mb_setup, - .teardown =3D rtl8365mb_teardown, - .phylink_validate =3D rtl8365mb_phylink_validate, - .phylink_mac_config =3D rtl8365mb_phylink_mac_config, - .phylink_mac_link_down =3D rtl8365mb_phylink_mac_link_down, - .phylink_mac_link_up =3D rtl8365mb_phylink_mac_link_up, - .port_stp_state_set =3D rtl8365mb_port_stp_state_set, - .get_strings =3D rtl8365mb_get_strings, - .get_ethtool_stats =3D rtl8365mb_get_ethtool_stats, - .get_sset_count =3D rtl8365mb_get_sset_count, - .get_eth_phy_stats =3D rtl8365mb_get_phy_stats, - .get_eth_mac_stats =3D rtl8365mb_get_mac_stats, - .get_eth_ctrl_stats =3D rtl8365mb_get_ctrl_stats, - .get_stats64 =3D rtl8365mb_get_stats64, -}; - -static const struct realtek_smi_ops rtl8365mb_smi_ops =3D { - .detect =3D rtl8365mb_detect, - .phy_read =3D rtl8365mb_phy_read, - .phy_write =3D rtl8365mb_phy_write, -}; - -const struct realtek_smi_variant rtl8365mb_variant =3D { - .ds_ops =3D &rtl8365mb_switch_ops, - .ops =3D &rtl8365mb_smi_ops, - .clk_delay =3D 10, - .cmd_read =3D 0xb9, - .cmd_write =3D 0xb8, - .chip_data_sz =3D sizeof(struct rtl8365mb), -}; -EXPORT_SYMBOL_GPL(rtl8365mb_variant); diff --git a/drivers/net/dsa/rtl8366.c b/drivers/net/dsa/rtl8366.c deleted file mode 100644 index bdb8d8d34880..000000000000 --- a/drivers/net/dsa/rtl8366.c +++ /dev/null @@ -1,448 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Realtek SMI library helpers for the RTL8366x variants - * RTL8366RB and RTL8366S - * - * Copyright (C) 2017 Linus Walleij - * Copyright (C) 2009-2010 Gabor Juhos - * Copyright (C) 2010 Antti Sepp=C3=A4l=C3=A4 - * Copyright (C) 2010 Roman Yeryomin - * Copyright (C) 2011 Colin Leitner - */ -#include -#include - -#include "realtek-smi-core.h" - -int rtl8366_mc_is_used(struct realtek_smi *smi, int mc_index, int *used) -{ - int ret; - int i; - - *used =3D 0; - for (i =3D 0; i < smi->num_ports; i++) { - int index =3D 0; - - ret =3D smi->ops->get_mc_index(smi, i, &index); - if (ret) - return ret; - - if (mc_index =3D=3D index) { - *used =3D 1; - break; - } - } - - return 0; -} -EXPORT_SYMBOL_GPL(rtl8366_mc_is_used); - -/** - * rtl8366_obtain_mc() - retrieve or allocate a VLAN member configuration - * @smi: the Realtek SMI device instance - * @vid: the VLAN ID to look up or allocate - * @vlanmc: the pointer will be assigned to a pointer to a valid member co= nfig - * if successful - * @return: index of a new member config or negative error number - */ -static int rtl8366_obtain_mc(struct realtek_smi *smi, int vid, - struct rtl8366_vlan_mc *vlanmc) -{ - struct rtl8366_vlan_4k vlan4k; - int ret; - int i; - - /* Try to find an existing member config entry for this VID */ - for (i =3D 0; i < smi->num_vlan_mc; i++) { - ret =3D smi->ops->get_vlan_mc(smi, i, vlanmc); - if (ret) { - dev_err(smi->dev, "error searching for VLAN MC %d for VID %d\n", - i, vid); - return ret; - } - - if (vid =3D=3D vlanmc->vid) - return i; - } - - /* We have no MC entry for this VID, try to find an empty one */ - for (i =3D 0; i < smi->num_vlan_mc; i++) { - ret =3D smi->ops->get_vlan_mc(smi, i, vlanmc); - if (ret) { - dev_err(smi->dev, "error searching for VLAN MC %d for VID %d\n", - i, vid); - return ret; - } - - if (vlanmc->vid =3D=3D 0 && vlanmc->member =3D=3D 0) { - /* Update the entry from the 4K table */ - ret =3D smi->ops->get_vlan_4k(smi, vid, &vlan4k); - if (ret) { - dev_err(smi->dev, "error looking for 4K VLAN MC %d for VID %d\n", - i, vid); - return ret; - } - - vlanmc->vid =3D vid; - vlanmc->member =3D vlan4k.member; - vlanmc->untag =3D vlan4k.untag; - vlanmc->fid =3D vlan4k.fid; - ret =3D smi->ops->set_vlan_mc(smi, i, vlanmc); - if (ret) { - dev_err(smi->dev, "unable to set/update VLAN MC %d for VID %d\n", - i, vid); - return ret; - } - - dev_dbg(smi->dev, "created new MC at index %d for VID %d\n", - i, vid); - return i; - } - } - - /* MC table is full, try to find an unused entry and replace it */ - for (i =3D 0; i < smi->num_vlan_mc; i++) { - int used; - - ret =3D rtl8366_mc_is_used(smi, i, &used); - if (ret) - return ret; - - if (!used) { - /* Update the entry from the 4K table */ - ret =3D smi->ops->get_vlan_4k(smi, vid, &vlan4k); - if (ret) - return ret; - - vlanmc->vid =3D vid; - vlanmc->member =3D vlan4k.member; - vlanmc->untag =3D vlan4k.untag; - vlanmc->fid =3D vlan4k.fid; - ret =3D smi->ops->set_vlan_mc(smi, i, vlanmc); - if (ret) { - dev_err(smi->dev, "unable to set/update VLAN MC %d for VID %d\n", - i, vid); - return ret; - } - dev_dbg(smi->dev, "recycled MC at index %i for VID %d\n", - i, vid); - return i; - } - } - - dev_err(smi->dev, "all VLAN member configurations are in use\n"); - return -ENOSPC; -} - -int rtl8366_set_vlan(struct realtek_smi *smi, int vid, u32 member, - u32 untag, u32 fid) -{ - struct rtl8366_vlan_mc vlanmc; - struct rtl8366_vlan_4k vlan4k; - int mc; - int ret; - - if (!smi->ops->is_vlan_valid(smi, vid)) - return -EINVAL; - - dev_dbg(smi->dev, - "setting VLAN%d 4k members: 0x%02x, untagged: 0x%02x\n", - vid, member, untag); - - /* Update the 4K table */ - ret =3D smi->ops->get_vlan_4k(smi, vid, &vlan4k); - if (ret) - return ret; - - vlan4k.member |=3D member; - vlan4k.untag |=3D untag; - vlan4k.fid =3D fid; - ret =3D smi->ops->set_vlan_4k(smi, &vlan4k); - if (ret) - return ret; - - dev_dbg(smi->dev, - "resulting VLAN%d 4k members: 0x%02x, untagged: 0x%02x\n", - vid, vlan4k.member, vlan4k.untag); - - /* Find or allocate a member config for this VID */ - ret =3D rtl8366_obtain_mc(smi, vid, &vlanmc); - if (ret < 0) - return ret; - mc =3D ret; - - /* Update the MC entry */ - vlanmc.member |=3D member; - vlanmc.untag |=3D untag; - vlanmc.fid =3D fid; - - /* Commit updates to the MC entry */ - ret =3D smi->ops->set_vlan_mc(smi, mc, &vlanmc); - if (ret) - dev_err(smi->dev, "failed to commit changes to VLAN MC index %d for VID = %d\n", - mc, vid); - else - dev_dbg(smi->dev, - "resulting VLAN%d MC members: 0x%02x, untagged: 0x%02x\n", - vid, vlanmc.member, vlanmc.untag); - - return ret; -} -EXPORT_SYMBOL_GPL(rtl8366_set_vlan); - -int rtl8366_set_pvid(struct realtek_smi *smi, unsigned int port, - unsigned int vid) -{ - struct rtl8366_vlan_mc vlanmc; - int mc; - int ret; - - if (!smi->ops->is_vlan_valid(smi, vid)) - return -EINVAL; - - /* Find or allocate a member config for this VID */ - ret =3D rtl8366_obtain_mc(smi, vid, &vlanmc); - if (ret < 0) - return ret; - mc =3D ret; - - ret =3D smi->ops->set_mc_index(smi, port, mc); - if (ret) { - dev_err(smi->dev, "set PVID: failed to set MC index %d for port %d\n", - mc, port); - return ret; - } - - dev_dbg(smi->dev, "set PVID: the PVID for port %d set to %d using existin= g MC index %d\n", - port, vid, mc); - - return 0; -} -EXPORT_SYMBOL_GPL(rtl8366_set_pvid); - -int rtl8366_enable_vlan4k(struct realtek_smi *smi, bool enable) -{ - int ret; - - /* To enable 4k VLAN, ordinary VLAN must be enabled first, - * but if we disable 4k VLAN it is fine to leave ordinary - * VLAN enabled. - */ - if (enable) { - /* Make sure VLAN is ON */ - ret =3D smi->ops->enable_vlan(smi, true); - if (ret) - return ret; - - smi->vlan_enabled =3D true; - } - - ret =3D smi->ops->enable_vlan4k(smi, enable); - if (ret) - return ret; - - smi->vlan4k_enabled =3D enable; - return 0; -} -EXPORT_SYMBOL_GPL(rtl8366_enable_vlan4k); - -int rtl8366_enable_vlan(struct realtek_smi *smi, bool enable) -{ - int ret; - - ret =3D smi->ops->enable_vlan(smi, enable); - if (ret) - return ret; - - smi->vlan_enabled =3D enable; - - /* If we turn VLAN off, make sure that we turn off - * 4k VLAN as well, if that happened to be on. - */ - if (!enable) { - smi->vlan4k_enabled =3D false; - ret =3D smi->ops->enable_vlan4k(smi, false); - } - - return ret; -} -EXPORT_SYMBOL_GPL(rtl8366_enable_vlan); - -int rtl8366_reset_vlan(struct realtek_smi *smi) -{ - struct rtl8366_vlan_mc vlanmc; - int ret; - int i; - - rtl8366_enable_vlan(smi, false); - rtl8366_enable_vlan4k(smi, false); - - /* Clear the 16 VLAN member configurations */ - vlanmc.vid =3D 0; - vlanmc.priority =3D 0; - vlanmc.member =3D 0; - vlanmc.untag =3D 0; - vlanmc.fid =3D 0; - for (i =3D 0; i < smi->num_vlan_mc; i++) { - ret =3D smi->ops->set_vlan_mc(smi, i, &vlanmc); - if (ret) - return ret; - } - - return 0; -} -EXPORT_SYMBOL_GPL(rtl8366_reset_vlan); - -int rtl8366_vlan_add(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan, - struct netlink_ext_ack *extack) -{ - bool untagged =3D !!(vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED); - bool pvid =3D !!(vlan->flags & BRIDGE_VLAN_INFO_PVID); - struct realtek_smi *smi =3D ds->priv; - u32 member =3D 0; - u32 untag =3D 0; - int ret; - - if (!smi->ops->is_vlan_valid(smi, vlan->vid)) { - NL_SET_ERR_MSG_MOD(extack, "VLAN ID not valid"); - return -EINVAL; - } - - /* Enable VLAN in the hardware - * FIXME: what's with this 4k business? - * Just rtl8366_enable_vlan() seems inconclusive. - */ - ret =3D rtl8366_enable_vlan4k(smi, true); - if (ret) { - NL_SET_ERR_MSG_MOD(extack, "Failed to enable VLAN 4K"); - return ret; - } - - dev_dbg(smi->dev, "add VLAN %d on port %d, %s, %s\n", - vlan->vid, port, untagged ? "untagged" : "tagged", - pvid ? "PVID" : "no PVID"); - - member |=3D BIT(port); - - if (untagged) - untag |=3D BIT(port); - - ret =3D rtl8366_set_vlan(smi, vlan->vid, member, untag, 0); - if (ret) { - dev_err(smi->dev, "failed to set up VLAN %04x", vlan->vid); - return ret; - } - - if (!pvid) - return 0; - - ret =3D rtl8366_set_pvid(smi, port, vlan->vid); - if (ret) { - dev_err(smi->dev, "failed to set PVID on port %d to VLAN %04x", - port, vlan->vid); - return ret; - } - - return 0; -} -EXPORT_SYMBOL_GPL(rtl8366_vlan_add); - -int rtl8366_vlan_del(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan) -{ - struct realtek_smi *smi =3D ds->priv; - int ret, i; - - dev_dbg(smi->dev, "del VLAN %d on port %d\n", vlan->vid, port); - - for (i =3D 0; i < smi->num_vlan_mc; i++) { - struct rtl8366_vlan_mc vlanmc; - - ret =3D smi->ops->get_vlan_mc(smi, i, &vlanmc); - if (ret) - return ret; - - if (vlan->vid =3D=3D vlanmc.vid) { - /* Remove this port from the VLAN */ - vlanmc.member &=3D ~BIT(port); - vlanmc.untag &=3D ~BIT(port); - /* - * If no ports are members of this VLAN - * anymore then clear the whole member - * config so it can be reused. - */ - if (!vlanmc.member) { - vlanmc.vid =3D 0; - vlanmc.priority =3D 0; - vlanmc.fid =3D 0; - } - ret =3D smi->ops->set_vlan_mc(smi, i, &vlanmc); - if (ret) { - dev_err(smi->dev, - "failed to remove VLAN %04x\n", - vlan->vid); - return ret; - } - break; - } - } - - return 0; -} -EXPORT_SYMBOL_GPL(rtl8366_vlan_del); - -void rtl8366_get_strings(struct dsa_switch *ds, int port, u32 stringset, - uint8_t *data) -{ - struct realtek_smi *smi =3D ds->priv; - struct rtl8366_mib_counter *mib; - int i; - - if (port >=3D smi->num_ports) - return; - - for (i =3D 0; i < smi->num_mib_counters; i++) { - mib =3D &smi->mib_counters[i]; - strncpy(data + i * ETH_GSTRING_LEN, - mib->name, ETH_GSTRING_LEN); - } -} -EXPORT_SYMBOL_GPL(rtl8366_get_strings); - -int rtl8366_get_sset_count(struct dsa_switch *ds, int port, int sset) -{ - struct realtek_smi *smi =3D ds->priv; - - /* We only support SS_STATS */ - if (sset !=3D ETH_SS_STATS) - return 0; - if (port >=3D smi->num_ports) - return -EINVAL; - - return smi->num_mib_counters; -} -EXPORT_SYMBOL_GPL(rtl8366_get_sset_count); - -void rtl8366_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *= data) -{ - struct realtek_smi *smi =3D ds->priv; - int i; - int ret; - - if (port >=3D smi->num_ports) - return; - - for (i =3D 0; i < smi->num_mib_counters; i++) { - struct rtl8366_mib_counter *mib; - u64 mibvalue =3D 0; - - mib =3D &smi->mib_counters[i]; - ret =3D smi->ops->get_mib_counter(smi, port, mib, &mibvalue); - if (ret) { - dev_err(smi->dev, "error reading MIB counter %s\n", - mib->name); - } - data[i] =3D mibvalue; - } -} -EXPORT_SYMBOL_GPL(rtl8366_get_ethtool_stats); diff --git a/drivers/net/dsa/rtl8366rb.c b/drivers/net/dsa/rtl8366rb.c deleted file mode 100644 index 03deacd83e61..000000000000 --- a/drivers/net/dsa/rtl8366rb.c +++ /dev/null @@ -1,1813 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Realtek SMI subdriver for the Realtek RTL8366RB ethernet switch - * - * This is a sparsely documented chip, the only viable documentation seems - * to be a patched up code drop from the vendor that appear in various - * GPL source trees. - * - * Copyright (C) 2017 Linus Walleij - * Copyright (C) 2009-2010 Gabor Juhos - * Copyright (C) 2010 Antti Sepp=C3=A4l=C3=A4 - * Copyright (C) 2010 Roman Yeryomin - * Copyright (C) 2011 Colin Leitner - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "realtek-smi-core.h" - -#define RTL8366RB_PORT_NUM_CPU 5 -#define RTL8366RB_NUM_PORTS 6 -#define RTL8366RB_PHY_NO_MAX 4 -#define RTL8366RB_PHY_ADDR_MAX 31 - -/* Switch Global Configuration register */ -#define RTL8366RB_SGCR 0x0000 -#define RTL8366RB_SGCR_EN_BC_STORM_CTRL BIT(0) -#define RTL8366RB_SGCR_MAX_LENGTH(a) ((a) << 4) -#define RTL8366RB_SGCR_MAX_LENGTH_MASK RTL8366RB_SGCR_MAX_LENGTH(0x3) -#define RTL8366RB_SGCR_MAX_LENGTH_1522 RTL8366RB_SGCR_MAX_LENGTH(0x0) -#define RTL8366RB_SGCR_MAX_LENGTH_1536 RTL8366RB_SGCR_MAX_LENGTH(0x1) -#define RTL8366RB_SGCR_MAX_LENGTH_1552 RTL8366RB_SGCR_MAX_LENGTH(0x2) -#define RTL8366RB_SGCR_MAX_LENGTH_16000 RTL8366RB_SGCR_MAX_LENGTH(0x3) -#define RTL8366RB_SGCR_EN_VLAN BIT(13) -#define RTL8366RB_SGCR_EN_VLAN_4KTB BIT(14) - -/* Port Enable Control register */ -#define RTL8366RB_PECR 0x0001 - -/* Switch per-port learning disablement register */ -#define RTL8366RB_PORT_LEARNDIS_CTRL 0x0002 - -/* Security control, actually aging register */ -#define RTL8366RB_SECURITY_CTRL 0x0003 - -#define RTL8366RB_SSCR2 0x0004 -#define RTL8366RB_SSCR2_DROP_UNKNOWN_DA BIT(0) - -/* Port Mode Control registers */ -#define RTL8366RB_PMC0 0x0005 -#define RTL8366RB_PMC0_SPI BIT(0) -#define RTL8366RB_PMC0_EN_AUTOLOAD BIT(1) -#define RTL8366RB_PMC0_PROBE BIT(2) -#define RTL8366RB_PMC0_DIS_BISR BIT(3) -#define RTL8366RB_PMC0_ADCTEST BIT(4) -#define RTL8366RB_PMC0_SRAM_DIAG BIT(5) -#define RTL8366RB_PMC0_EN_SCAN BIT(6) -#define RTL8366RB_PMC0_P4_IOMODE_SHIFT 7 -#define RTL8366RB_PMC0_P4_IOMODE_MASK GENMASK(9, 7) -#define RTL8366RB_PMC0_P5_IOMODE_SHIFT 10 -#define RTL8366RB_PMC0_P5_IOMODE_MASK GENMASK(12, 10) -#define RTL8366RB_PMC0_SDSMODE_SHIFT 13 -#define RTL8366RB_PMC0_SDSMODE_MASK GENMASK(15, 13) -#define RTL8366RB_PMC1 0x0006 - -/* Port Mirror Control Register */ -#define RTL8366RB_PMCR 0x0007 -#define RTL8366RB_PMCR_SOURCE_PORT(a) (a) -#define RTL8366RB_PMCR_SOURCE_PORT_MASK 0x000f -#define RTL8366RB_PMCR_MONITOR_PORT(a) ((a) << 4) -#define RTL8366RB_PMCR_MONITOR_PORT_MASK 0x00f0 -#define RTL8366RB_PMCR_MIRROR_RX BIT(8) -#define RTL8366RB_PMCR_MIRROR_TX BIT(9) -#define RTL8366RB_PMCR_MIRROR_SPC BIT(10) -#define RTL8366RB_PMCR_MIRROR_ISO BIT(11) - -/* bits 0..7 =3D port 0, bits 8..15 =3D port 1 */ -#define RTL8366RB_PAACR0 0x0010 -/* bits 0..7 =3D port 2, bits 8..15 =3D port 3 */ -#define RTL8366RB_PAACR1 0x0011 -/* bits 0..7 =3D port 4, bits 8..15 =3D port 5 */ -#define RTL8366RB_PAACR2 0x0012 -#define RTL8366RB_PAACR_SPEED_10M 0 -#define RTL8366RB_PAACR_SPEED_100M 1 -#define RTL8366RB_PAACR_SPEED_1000M 2 -#define RTL8366RB_PAACR_FULL_DUPLEX BIT(2) -#define RTL8366RB_PAACR_LINK_UP BIT(4) -#define RTL8366RB_PAACR_TX_PAUSE BIT(5) -#define RTL8366RB_PAACR_RX_PAUSE BIT(6) -#define RTL8366RB_PAACR_AN BIT(7) - -#define RTL8366RB_PAACR_CPU_PORT (RTL8366RB_PAACR_SPEED_1000M | \ - RTL8366RB_PAACR_FULL_DUPLEX | \ - RTL8366RB_PAACR_LINK_UP | \ - RTL8366RB_PAACR_TX_PAUSE | \ - RTL8366RB_PAACR_RX_PAUSE) - -/* bits 0..7 =3D port 0, bits 8..15 =3D port 1 */ -#define RTL8366RB_PSTAT0 0x0014 -/* bits 0..7 =3D port 2, bits 8..15 =3D port 3 */ -#define RTL8366RB_PSTAT1 0x0015 -/* bits 0..7 =3D port 4, bits 8..15 =3D port 5 */ -#define RTL8366RB_PSTAT2 0x0016 - -#define RTL8366RB_POWER_SAVING_REG 0x0021 - -/* Spanning tree status (STP) control, two bits per port per FID */ -#define RTL8366RB_STP_STATE_BASE 0x0050 /* 0x0050..0x0057 */ -#define RTL8366RB_STP_STATE_DISABLED 0x0 -#define RTL8366RB_STP_STATE_BLOCKING 0x1 -#define RTL8366RB_STP_STATE_LEARNING 0x2 -#define RTL8366RB_STP_STATE_FORWARDING 0x3 -#define RTL8366RB_STP_MASK GENMASK(1, 0) -#define RTL8366RB_STP_STATE(port, state) \ - ((state) << ((port) * 2)) -#define RTL8366RB_STP_STATE_MASK(port) \ - RTL8366RB_STP_STATE((port), RTL8366RB_STP_MASK) - -/* CPU port control reg */ -#define RTL8368RB_CPU_CTRL_REG 0x0061 -#define RTL8368RB_CPU_PORTS_MSK 0x00FF -/* Disables inserting custom tag length/type 0x8899 */ -#define RTL8368RB_CPU_NO_TAG BIT(15) - -#define RTL8366RB_SMAR0 0x0070 /* bits 0..15 */ -#define RTL8366RB_SMAR1 0x0071 /* bits 16..31 */ -#define RTL8366RB_SMAR2 0x0072 /* bits 32..47 */ - -#define RTL8366RB_RESET_CTRL_REG 0x0100 -#define RTL8366RB_CHIP_CTRL_RESET_HW BIT(0) -#define RTL8366RB_CHIP_CTRL_RESET_SW BIT(1) - -#define RTL8366RB_CHIP_ID_REG 0x0509 -#define RTL8366RB_CHIP_ID_8366 0x5937 -#define RTL8366RB_CHIP_VERSION_CTRL_REG 0x050A -#define RTL8366RB_CHIP_VERSION_MASK 0xf - -/* PHY registers control */ -#define RTL8366RB_PHY_ACCESS_CTRL_REG 0x8000 -#define RTL8366RB_PHY_CTRL_READ BIT(0) -#define RTL8366RB_PHY_CTRL_WRITE 0 -#define RTL8366RB_PHY_ACCESS_BUSY_REG 0x8001 -#define RTL8366RB_PHY_INT_BUSY BIT(0) -#define RTL8366RB_PHY_EXT_BUSY BIT(4) -#define RTL8366RB_PHY_ACCESS_DATA_REG 0x8002 -#define RTL8366RB_PHY_EXT_CTRL_REG 0x8010 -#define RTL8366RB_PHY_EXT_WRDATA_REG 0x8011 -#define RTL8366RB_PHY_EXT_RDDATA_REG 0x8012 - -#define RTL8366RB_PHY_REG_MASK 0x1f -#define RTL8366RB_PHY_PAGE_OFFSET 5 -#define RTL8366RB_PHY_PAGE_MASK (0xf << 5) -#define RTL8366RB_PHY_NO_OFFSET 9 -#define RTL8366RB_PHY_NO_MASK (0x1f << 9) - -/* VLAN Ingress Control Register 1, one bit per port. - * bit 0 .. 5 will make the switch drop ingress frames without - * VID such as untagged or priority-tagged frames for respective - * port. - * bit 6 .. 11 will make the switch drop ingress frames carrying - * a C-tag with VID !=3D 0 for respective port. - */ -#define RTL8366RB_VLAN_INGRESS_CTRL1_REG 0x037E -#define RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port) (BIT((port)) | BIT((port) = + 6)) - -/* VLAN Ingress Control Register 2, one bit per port. - * bit0 .. bit5 will make the switch drop all ingress frames with - * a VLAN classification that does not include the port is in its - * member set. - */ -#define RTL8366RB_VLAN_INGRESS_CTRL2_REG 0x037f - -/* LED control registers */ -#define RTL8366RB_LED_BLINKRATE_REG 0x0430 -#define RTL8366RB_LED_BLINKRATE_MASK 0x0007 -#define RTL8366RB_LED_BLINKRATE_28MS 0x0000 -#define RTL8366RB_LED_BLINKRATE_56MS 0x0001 -#define RTL8366RB_LED_BLINKRATE_84MS 0x0002 -#define RTL8366RB_LED_BLINKRATE_111MS 0x0003 -#define RTL8366RB_LED_BLINKRATE_222MS 0x0004 -#define RTL8366RB_LED_BLINKRATE_446MS 0x0005 - -#define RTL8366RB_LED_CTRL_REG 0x0431 -#define RTL8366RB_LED_OFF 0x0 -#define RTL8366RB_LED_DUP_COL 0x1 -#define RTL8366RB_LED_LINK_ACT 0x2 -#define RTL8366RB_LED_SPD1000 0x3 -#define RTL8366RB_LED_SPD100 0x4 -#define RTL8366RB_LED_SPD10 0x5 -#define RTL8366RB_LED_SPD1000_ACT 0x6 -#define RTL8366RB_LED_SPD100_ACT 0x7 -#define RTL8366RB_LED_SPD10_ACT 0x8 -#define RTL8366RB_LED_SPD100_10_ACT 0x9 -#define RTL8366RB_LED_FIBER 0xa -#define RTL8366RB_LED_AN_FAULT 0xb -#define RTL8366RB_LED_LINK_RX 0xc -#define RTL8366RB_LED_LINK_TX 0xd -#define RTL8366RB_LED_MASTER 0xe -#define RTL8366RB_LED_FORCE 0xf -#define RTL8366RB_LED_0_1_CTRL_REG 0x0432 -#define RTL8366RB_LED_1_OFFSET 6 -#define RTL8366RB_LED_2_3_CTRL_REG 0x0433 -#define RTL8366RB_LED_3_OFFSET 6 - -#define RTL8366RB_MIB_COUNT 33 -#define RTL8366RB_GLOBAL_MIB_COUNT 1 -#define RTL8366RB_MIB_COUNTER_PORT_OFFSET 0x0050 -#define RTL8366RB_MIB_COUNTER_BASE 0x1000 -#define RTL8366RB_MIB_CTRL_REG 0x13F0 -#define RTL8366RB_MIB_CTRL_USER_MASK 0x0FFC -#define RTL8366RB_MIB_CTRL_BUSY_MASK BIT(0) -#define RTL8366RB_MIB_CTRL_RESET_MASK BIT(1) -#define RTL8366RB_MIB_CTRL_PORT_RESET(_p) BIT(2 + (_p)) -#define RTL8366RB_MIB_CTRL_GLOBAL_RESET BIT(11) - -#define RTL8366RB_PORT_VLAN_CTRL_BASE 0x0063 -#define RTL8366RB_PORT_VLAN_CTRL_REG(_p) \ - (RTL8366RB_PORT_VLAN_CTRL_BASE + (_p) / 4) -#define RTL8366RB_PORT_VLAN_CTRL_MASK 0xf -#define RTL8366RB_PORT_VLAN_CTRL_SHIFT(_p) (4 * ((_p) % 4)) - -#define RTL8366RB_VLAN_TABLE_READ_BASE 0x018C -#define RTL8366RB_VLAN_TABLE_WRITE_BASE 0x0185 - -#define RTL8366RB_TABLE_ACCESS_CTRL_REG 0x0180 -#define RTL8366RB_TABLE_VLAN_READ_CTRL 0x0E01 -#define RTL8366RB_TABLE_VLAN_WRITE_CTRL 0x0F01 - -#define RTL8366RB_VLAN_MC_BASE(_x) (0x0020 + (_x) * 3) - -#define RTL8366RB_PORT_LINK_STATUS_BASE 0x0014 -#define RTL8366RB_PORT_STATUS_SPEED_MASK 0x0003 -#define RTL8366RB_PORT_STATUS_DUPLEX_MASK 0x0004 -#define RTL8366RB_PORT_STATUS_LINK_MASK 0x0010 -#define RTL8366RB_PORT_STATUS_TXPAUSE_MASK 0x0020 -#define RTL8366RB_PORT_STATUS_RXPAUSE_MASK 0x0040 -#define RTL8366RB_PORT_STATUS_AN_MASK 0x0080 - -#define RTL8366RB_NUM_VLANS 16 -#define RTL8366RB_NUM_LEDGROUPS 4 -#define RTL8366RB_NUM_VIDS 4096 -#define RTL8366RB_PRIORITYMAX 7 -#define RTL8366RB_NUM_FIDS 8 -#define RTL8366RB_FIDMAX 7 - -#define RTL8366RB_PORT_1 BIT(0) /* In userspace port 0 */ -#define RTL8366RB_PORT_2 BIT(1) /* In userspace port 1 */ -#define RTL8366RB_PORT_3 BIT(2) /* In userspace port 2 */ -#define RTL8366RB_PORT_4 BIT(3) /* In userspace port 3 */ -#define RTL8366RB_PORT_5 BIT(4) /* In userspace port 4 */ - -#define RTL8366RB_PORT_CPU BIT(5) /* CPU port */ - -#define RTL8366RB_PORT_ALL (RTL8366RB_PORT_1 | \ - RTL8366RB_PORT_2 | \ - RTL8366RB_PORT_3 | \ - RTL8366RB_PORT_4 | \ - RTL8366RB_PORT_5 | \ - RTL8366RB_PORT_CPU) - -#define RTL8366RB_PORT_ALL_BUT_CPU (RTL8366RB_PORT_1 | \ - RTL8366RB_PORT_2 | \ - RTL8366RB_PORT_3 | \ - RTL8366RB_PORT_4 | \ - RTL8366RB_PORT_5) - -#define RTL8366RB_PORT_ALL_EXTERNAL (RTL8366RB_PORT_1 | \ - RTL8366RB_PORT_2 | \ - RTL8366RB_PORT_3 | \ - RTL8366RB_PORT_4) - -#define RTL8366RB_PORT_ALL_INTERNAL RTL8366RB_PORT_CPU - -/* First configuration word per member config, VID and prio */ -#define RTL8366RB_VLAN_VID_MASK 0xfff -#define RTL8366RB_VLAN_PRIORITY_SHIFT 12 -#define RTL8366RB_VLAN_PRIORITY_MASK 0x7 -/* Second configuration word per member config, member and untagged */ -#define RTL8366RB_VLAN_UNTAG_SHIFT 8 -#define RTL8366RB_VLAN_UNTAG_MASK 0xff -#define RTL8366RB_VLAN_MEMBER_MASK 0xff -/* Third config word per member config, STAG currently unused */ -#define RTL8366RB_VLAN_STAG_MBR_MASK 0xff -#define RTL8366RB_VLAN_STAG_MBR_SHIFT 8 -#define RTL8366RB_VLAN_STAG_IDX_MASK 0x7 -#define RTL8366RB_VLAN_STAG_IDX_SHIFT 5 -#define RTL8366RB_VLAN_FID_MASK 0x7 - -/* Port ingress bandwidth control */ -#define RTL8366RB_IB_BASE 0x0200 -#define RTL8366RB_IB_REG(pnum) (RTL8366RB_IB_BASE + (pnum)) -#define RTL8366RB_IB_BDTH_MASK 0x3fff -#define RTL8366RB_IB_PREIFG BIT(14) - -/* Port egress bandwidth control */ -#define RTL8366RB_EB_BASE 0x02d1 -#define RTL8366RB_EB_REG(pnum) (RTL8366RB_EB_BASE + (pnum)) -#define RTL8366RB_EB_BDTH_MASK 0x3fff -#define RTL8366RB_EB_PREIFG_REG 0x02f8 -#define RTL8366RB_EB_PREIFG BIT(9) - -#define RTL8366RB_BDTH_SW_MAX 1048512 /* 1048576? */ -#define RTL8366RB_BDTH_UNIT 64 -#define RTL8366RB_BDTH_REG_DEFAULT 16383 - -/* QOS */ -#define RTL8366RB_QOS BIT(15) -/* Include/Exclude Preamble and IFG (20 bytes). 0:Exclude, 1:Include. */ -#define RTL8366RB_QOS_DEFAULT_PREIFG 1 - -/* Interrupt handling */ -#define RTL8366RB_INTERRUPT_CONTROL_REG 0x0440 -#define RTL8366RB_INTERRUPT_POLARITY BIT(0) -#define RTL8366RB_P4_RGMII_LED BIT(2) -#define RTL8366RB_INTERRUPT_MASK_REG 0x0441 -#define RTL8366RB_INTERRUPT_LINK_CHGALL GENMASK(11, 0) -#define RTL8366RB_INTERRUPT_ACLEXCEED BIT(8) -#define RTL8366RB_INTERRUPT_STORMEXCEED BIT(9) -#define RTL8366RB_INTERRUPT_P4_FIBER BIT(12) -#define RTL8366RB_INTERRUPT_P4_UTP BIT(13) -#define RTL8366RB_INTERRUPT_VALID (RTL8366RB_INTERRUPT_LINK_CHGALL | \ - RTL8366RB_INTERRUPT_ACLEXCEED | \ - RTL8366RB_INTERRUPT_STORMEXCEED | \ - RTL8366RB_INTERRUPT_P4_FIBER | \ - RTL8366RB_INTERRUPT_P4_UTP) -#define RTL8366RB_INTERRUPT_STATUS_REG 0x0442 -#define RTL8366RB_NUM_INTERRUPT 14 /* 0..13 */ - -/* Port isolation registers */ -#define RTL8366RB_PORT_ISO_BASE 0x0F08 -#define RTL8366RB_PORT_ISO(pnum) (RTL8366RB_PORT_ISO_BASE + (pnum)) -#define RTL8366RB_PORT_ISO_EN BIT(0) -#define RTL8366RB_PORT_ISO_PORTS_MASK GENMASK(7, 1) -#define RTL8366RB_PORT_ISO_PORTS(pmask) ((pmask) << 1) - -/* bits 0..5 enable force when cleared */ -#define RTL8366RB_MAC_FORCE_CTRL_REG 0x0F11 - -#define RTL8366RB_OAM_PARSER_REG 0x0F14 -#define RTL8366RB_OAM_MULTIPLEXER_REG 0x0F15 - -#define RTL8366RB_GREEN_FEATURE_REG 0x0F51 -#define RTL8366RB_GREEN_FEATURE_MSK 0x0007 -#define RTL8366RB_GREEN_FEATURE_TX BIT(0) -#define RTL8366RB_GREEN_FEATURE_RX BIT(2) - -/** - * struct rtl8366rb - RTL8366RB-specific data - * @max_mtu: per-port max MTU setting - * @pvid_enabled: if PVID is set for respective port - */ -struct rtl8366rb { - unsigned int max_mtu[RTL8366RB_NUM_PORTS]; - bool pvid_enabled[RTL8366RB_NUM_PORTS]; -}; - -static struct rtl8366_mib_counter rtl8366rb_mib_counters[] =3D { - { 0, 0, 4, "IfInOctets" }, - { 0, 4, 4, "EtherStatsOctets" }, - { 0, 8, 2, "EtherStatsUnderSizePkts" }, - { 0, 10, 2, "EtherFragments" }, - { 0, 12, 2, "EtherStatsPkts64Octets" }, - { 0, 14, 2, "EtherStatsPkts65to127Octets" }, - { 0, 16, 2, "EtherStatsPkts128to255Octets" }, - { 0, 18, 2, "EtherStatsPkts256to511Octets" }, - { 0, 20, 2, "EtherStatsPkts512to1023Octets" }, - { 0, 22, 2, "EtherStatsPkts1024to1518Octets" }, - { 0, 24, 2, "EtherOversizeStats" }, - { 0, 26, 2, "EtherStatsJabbers" }, - { 0, 28, 2, "IfInUcastPkts" }, - { 0, 30, 2, "EtherStatsMulticastPkts" }, - { 0, 32, 2, "EtherStatsBroadcastPkts" }, - { 0, 34, 2, "EtherStatsDropEvents" }, - { 0, 36, 2, "Dot3StatsFCSErrors" }, - { 0, 38, 2, "Dot3StatsSymbolErrors" }, - { 0, 40, 2, "Dot3InPauseFrames" }, - { 0, 42, 2, "Dot3ControlInUnknownOpcodes" }, - { 0, 44, 4, "IfOutOctets" }, - { 0, 48, 2, "Dot3StatsSingleCollisionFrames" }, - { 0, 50, 2, "Dot3StatMultipleCollisionFrames" }, - { 0, 52, 2, "Dot3sDeferredTransmissions" }, - { 0, 54, 2, "Dot3StatsLateCollisions" }, - { 0, 56, 2, "EtherStatsCollisions" }, - { 0, 58, 2, "Dot3StatsExcessiveCollisions" }, - { 0, 60, 2, "Dot3OutPauseFrames" }, - { 0, 62, 2, "Dot1dBasePortDelayExceededDiscards" }, - { 0, 64, 2, "Dot1dTpPortInDiscards" }, - { 0, 66, 2, "IfOutUcastPkts" }, - { 0, 68, 2, "IfOutMulticastPkts" }, - { 0, 70, 2, "IfOutBroadcastPkts" }, -}; - -static int rtl8366rb_get_mib_counter(struct realtek_smi *smi, - int port, - struct rtl8366_mib_counter *mib, - u64 *mibvalue) -{ - u32 addr, val; - int ret; - int i; - - addr =3D RTL8366RB_MIB_COUNTER_BASE + - RTL8366RB_MIB_COUNTER_PORT_OFFSET * (port) + - mib->offset; - - /* Writing access counter address first - * then ASIC will prepare 64bits counter wait for being retrived - */ - ret =3D regmap_write(smi->map, addr, 0); /* Write whatever */ - if (ret) - return ret; - - /* Read MIB control register */ - ret =3D regmap_read(smi->map, RTL8366RB_MIB_CTRL_REG, &val); - if (ret) - return -EIO; - - if (val & RTL8366RB_MIB_CTRL_BUSY_MASK) - return -EBUSY; - - if (val & RTL8366RB_MIB_CTRL_RESET_MASK) - return -EIO; - - /* Read each individual MIB 16 bits at the time */ - *mibvalue =3D 0; - for (i =3D mib->length; i > 0; i--) { - ret =3D regmap_read(smi->map, addr + (i - 1), &val); - if (ret) - return ret; - *mibvalue =3D (*mibvalue << 16) | (val & 0xFFFF); - } - return 0; -} - -static u32 rtl8366rb_get_irqmask(struct irq_data *d) -{ - int line =3D irqd_to_hwirq(d); - u32 val; - - /* For line interrupts we combine link down in bits - * 6..11 with link up in bits 0..5 into one interrupt. - */ - if (line < 12) - val =3D BIT(line) | BIT(line + 6); - else - val =3D BIT(line); - return val; -} - -static void rtl8366rb_mask_irq(struct irq_data *d) -{ - struct realtek_smi *smi =3D irq_data_get_irq_chip_data(d); - int ret; - - ret =3D regmap_update_bits(smi->map, RTL8366RB_INTERRUPT_MASK_REG, - rtl8366rb_get_irqmask(d), 0); - if (ret) - dev_err(smi->dev, "could not mask IRQ\n"); -} - -static void rtl8366rb_unmask_irq(struct irq_data *d) -{ - struct realtek_smi *smi =3D irq_data_get_irq_chip_data(d); - int ret; - - ret =3D regmap_update_bits(smi->map, RTL8366RB_INTERRUPT_MASK_REG, - rtl8366rb_get_irqmask(d), - rtl8366rb_get_irqmask(d)); - if (ret) - dev_err(smi->dev, "could not unmask IRQ\n"); -} - -static irqreturn_t rtl8366rb_irq(int irq, void *data) -{ - struct realtek_smi *smi =3D data; - u32 stat; - int ret; - - /* This clears the IRQ status register */ - ret =3D regmap_read(smi->map, RTL8366RB_INTERRUPT_STATUS_REG, - &stat); - if (ret) { - dev_err(smi->dev, "can't read interrupt status\n"); - return IRQ_NONE; - } - stat &=3D RTL8366RB_INTERRUPT_VALID; - if (!stat) - return IRQ_NONE; - while (stat) { - int line =3D __ffs(stat); - int child_irq; - - stat &=3D ~BIT(line); - /* For line interrupts we combine link down in bits - * 6..11 with link up in bits 0..5 into one interrupt. - */ - if (line < 12 && line > 5) - line -=3D 5; - child_irq =3D irq_find_mapping(smi->irqdomain, line); - handle_nested_irq(child_irq); - } - return IRQ_HANDLED; -} - -static struct irq_chip rtl8366rb_irq_chip =3D { - .name =3D "RTL8366RB", - .irq_mask =3D rtl8366rb_mask_irq, - .irq_unmask =3D rtl8366rb_unmask_irq, -}; - -static int rtl8366rb_irq_map(struct irq_domain *domain, unsigned int irq, - irq_hw_number_t hwirq) -{ - irq_set_chip_data(irq, domain->host_data); - irq_set_chip_and_handler(irq, &rtl8366rb_irq_chip, handle_simple_irq); - irq_set_nested_thread(irq, 1); - irq_set_noprobe(irq); - - return 0; -} - -static void rtl8366rb_irq_unmap(struct irq_domain *d, unsigned int irq) -{ - irq_set_nested_thread(irq, 0); - irq_set_chip_and_handler(irq, NULL, NULL); - irq_set_chip_data(irq, NULL); -} - -static const struct irq_domain_ops rtl8366rb_irqdomain_ops =3D { - .map =3D rtl8366rb_irq_map, - .unmap =3D rtl8366rb_irq_unmap, - .xlate =3D irq_domain_xlate_onecell, -}; - -static int rtl8366rb_setup_cascaded_irq(struct realtek_smi *smi) -{ - struct device_node *intc; - unsigned long irq_trig; - int irq; - int ret; - u32 val; - int i; - - intc =3D of_get_child_by_name(smi->dev->of_node, "interrupt-controller"); - if (!intc) { - dev_err(smi->dev, "missing child interrupt-controller node\n"); - return -EINVAL; - } - /* RB8366RB IRQs cascade off this one */ - irq =3D of_irq_get(intc, 0); - if (irq <=3D 0) { - dev_err(smi->dev, "failed to get parent IRQ\n"); - ret =3D irq ? irq : -EINVAL; - goto out_put_node; - } - - /* This clears the IRQ status register */ - ret =3D regmap_read(smi->map, RTL8366RB_INTERRUPT_STATUS_REG, - &val); - if (ret) { - dev_err(smi->dev, "can't read interrupt status\n"); - goto out_put_node; - } - - /* Fetch IRQ edge information from the descriptor */ - irq_trig =3D irqd_get_trigger_type(irq_get_irq_data(irq)); - switch (irq_trig) { - case IRQF_TRIGGER_RISING: - case IRQF_TRIGGER_HIGH: - dev_info(smi->dev, "active high/rising IRQ\n"); - val =3D 0; - break; - case IRQF_TRIGGER_FALLING: - case IRQF_TRIGGER_LOW: - dev_info(smi->dev, "active low/falling IRQ\n"); - val =3D RTL8366RB_INTERRUPT_POLARITY; - break; - } - ret =3D regmap_update_bits(smi->map, RTL8366RB_INTERRUPT_CONTROL_REG, - RTL8366RB_INTERRUPT_POLARITY, - val); - if (ret) { - dev_err(smi->dev, "could not configure IRQ polarity\n"); - goto out_put_node; - } - - ret =3D devm_request_threaded_irq(smi->dev, irq, NULL, - rtl8366rb_irq, IRQF_ONESHOT, - "RTL8366RB", smi); - if (ret) { - dev_err(smi->dev, "unable to request irq: %d\n", ret); - goto out_put_node; - } - smi->irqdomain =3D irq_domain_add_linear(intc, - RTL8366RB_NUM_INTERRUPT, - &rtl8366rb_irqdomain_ops, - smi); - if (!smi->irqdomain) { - dev_err(smi->dev, "failed to create IRQ domain\n"); - ret =3D -EINVAL; - goto out_put_node; - } - for (i =3D 0; i < smi->num_ports; i++) - irq_set_parent(irq_create_mapping(smi->irqdomain, i), irq); - -out_put_node: - of_node_put(intc); - return ret; -} - -static int rtl8366rb_set_addr(struct realtek_smi *smi) -{ - u8 addr[ETH_ALEN]; - u16 val; - int ret; - - eth_random_addr(addr); - - dev_info(smi->dev, "set MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); - val =3D addr[0] << 8 | addr[1]; - ret =3D regmap_write(smi->map, RTL8366RB_SMAR0, val); - if (ret) - return ret; - val =3D addr[2] << 8 | addr[3]; - ret =3D regmap_write(smi->map, RTL8366RB_SMAR1, val); - if (ret) - return ret; - val =3D addr[4] << 8 | addr[5]; - ret =3D regmap_write(smi->map, RTL8366RB_SMAR2, val); - if (ret) - return ret; - - return 0; -} - -/* Found in a vendor driver */ - -/* Struct for handling the jam tables' entries */ -struct rtl8366rb_jam_tbl_entry { - u16 reg; - u16 val; -}; - -/* For the "version 0" early silicon, appear in most source releases */ -static const struct rtl8366rb_jam_tbl_entry rtl8366rb_init_jam_ver_0[] =3D= { - {0x000B, 0x0001}, {0x03A6, 0x0100}, {0x03A7, 0x0001}, {0x02D1, 0x3FFF}, - {0x02D2, 0x3FFF}, {0x02D3, 0x3FFF}, {0x02D4, 0x3FFF}, {0x02D5, 0x3FFF}, - {0x02D6, 0x3FFF}, {0x02D7, 0x3FFF}, {0x02D8, 0x3FFF}, {0x022B, 0x0688}, - {0x022C, 0x0FAC}, {0x03D0, 0x4688}, {0x03D1, 0x01F5}, {0x0000, 0x0830}, - {0x02F9, 0x0200}, {0x02F7, 0x7FFF}, {0x02F8, 0x03FF}, {0x0080, 0x03E8}, - {0x0081, 0x00CE}, {0x0082, 0x00DA}, {0x0083, 0x0230}, {0xBE0F, 0x2000}, - {0x0231, 0x422A}, {0x0232, 0x422A}, {0x0233, 0x422A}, {0x0234, 0x422A}, - {0x0235, 0x422A}, {0x0236, 0x422A}, {0x0237, 0x422A}, {0x0238, 0x422A}, - {0x0239, 0x422A}, {0x023A, 0x422A}, {0x023B, 0x422A}, {0x023C, 0x422A}, - {0x023D, 0x422A}, {0x023E, 0x422A}, {0x023F, 0x422A}, {0x0240, 0x422A}, - {0x0241, 0x422A}, {0x0242, 0x422A}, {0x0243, 0x422A}, {0x0244, 0x422A}, - {0x0245, 0x422A}, {0x0246, 0x422A}, {0x0247, 0x422A}, {0x0248, 0x422A}, - {0x0249, 0x0146}, {0x024A, 0x0146}, {0x024B, 0x0146}, {0xBE03, 0xC961}, - {0x024D, 0x0146}, {0x024E, 0x0146}, {0x024F, 0x0146}, {0x0250, 0x0146}, - {0xBE64, 0x0226}, {0x0252, 0x0146}, {0x0253, 0x0146}, {0x024C, 0x0146}, - {0x0251, 0x0146}, {0x0254, 0x0146}, {0xBE62, 0x3FD0}, {0x0084, 0x0320}, - {0x0255, 0x0146}, {0x0256, 0x0146}, {0x0257, 0x0146}, {0x0258, 0x0146}, - {0x0259, 0x0146}, {0x025A, 0x0146}, {0x025B, 0x0146}, {0x025C, 0x0146}, - {0x025D, 0x0146}, {0x025E, 0x0146}, {0x025F, 0x0146}, {0x0260, 0x0146}, - {0x0261, 0xA23F}, {0x0262, 0x0294}, {0x0263, 0xA23F}, {0x0264, 0x0294}, - {0x0265, 0xA23F}, {0x0266, 0x0294}, {0x0267, 0xA23F}, {0x0268, 0x0294}, - {0x0269, 0xA23F}, {0x026A, 0x0294}, {0x026B, 0xA23F}, {0x026C, 0x0294}, - {0x026D, 0xA23F}, {0x026E, 0x0294}, {0x026F, 0xA23F}, {0x0270, 0x0294}, - {0x02F5, 0x0048}, {0xBE09, 0x0E00}, {0xBE1E, 0x0FA0}, {0xBE14, 0x8448}, - {0xBE15, 0x1007}, {0xBE4A, 0xA284}, {0xC454, 0x3F0B}, {0xC474, 0x3F0B}, - {0xBE48, 0x3672}, {0xBE4B, 0x17A7}, {0xBE4C, 0x0B15}, {0xBE52, 0x0EDD}, - {0xBE49, 0x8C00}, {0xBE5B, 0x785C}, {0xBE5C, 0x785C}, {0xBE5D, 0x785C}, - {0xBE61, 0x368A}, {0xBE63, 0x9B84}, {0xC456, 0xCC13}, {0xC476, 0xCC13}, - {0xBE65, 0x307D}, {0xBE6D, 0x0005}, {0xBE6E, 0xE120}, {0xBE2E, 0x7BAF}, -}; - -/* This v1 init sequence is from Belkin F5D8235 U-Boot release */ -static const struct rtl8366rb_jam_tbl_entry rtl8366rb_init_jam_ver_1[] =3D= { - {0x0000, 0x0830}, {0x0001, 0x8000}, {0x0400, 0x8130}, {0xBE78, 0x3C3C}, - {0x0431, 0x5432}, {0xBE37, 0x0CE4}, {0x02FA, 0xFFDF}, {0x02FB, 0xFFE0}, - {0xC44C, 0x1585}, {0xC44C, 0x1185}, {0xC44C, 0x1585}, {0xC46C, 0x1585}, - {0xC46C, 0x1185}, {0xC46C, 0x1585}, {0xC451, 0x2135}, {0xC471, 0x2135}, - {0xBE10, 0x8140}, {0xBE15, 0x0007}, {0xBE6E, 0xE120}, {0xBE69, 0xD20F}, - {0xBE6B, 0x0320}, {0xBE24, 0xB000}, {0xBE23, 0xFF51}, {0xBE22, 0xDF20}, - {0xBE21, 0x0140}, {0xBE20, 0x00BB}, {0xBE24, 0xB800}, {0xBE24, 0x0000}, - {0xBE24, 0x7000}, {0xBE23, 0xFF51}, {0xBE22, 0xDF60}, {0xBE21, 0x0140}, - {0xBE20, 0x0077}, {0xBE24, 0x7800}, {0xBE24, 0x0000}, {0xBE2E, 0x7B7A}, - {0xBE36, 0x0CE4}, {0x02F5, 0x0048}, {0xBE77, 0x2940}, {0x000A, 0x83E0}, - {0xBE79, 0x3C3C}, {0xBE00, 0x1340}, -}; - -/* This v2 init sequence is from Belkin F5D8235 U-Boot release */ -static const struct rtl8366rb_jam_tbl_entry rtl8366rb_init_jam_ver_2[] =3D= { - {0x0450, 0x0000}, {0x0400, 0x8130}, {0x000A, 0x83ED}, {0x0431, 0x5432}, - {0xC44F, 0x6250}, {0xC46F, 0x6250}, {0xC456, 0x0C14}, {0xC476, 0x0C14}, - {0xC44C, 0x1C85}, {0xC44C, 0x1885}, {0xC44C, 0x1C85}, {0xC46C, 0x1C85}, - {0xC46C, 0x1885}, {0xC46C, 0x1C85}, {0xC44C, 0x0885}, {0xC44C, 0x0881}, - {0xC44C, 0x0885}, {0xC46C, 0x0885}, {0xC46C, 0x0881}, {0xC46C, 0x0885}, - {0xBE2E, 0x7BA7}, {0xBE36, 0x1000}, {0xBE37, 0x1000}, {0x8000, 0x0001}, - {0xBE69, 0xD50F}, {0x8000, 0x0000}, {0xBE69, 0xD50F}, {0xBE6E, 0x0320}, - {0xBE77, 0x2940}, {0xBE78, 0x3C3C}, {0xBE79, 0x3C3C}, {0xBE6E, 0xE120}, - {0x8000, 0x0001}, {0xBE15, 0x1007}, {0x8000, 0x0000}, {0xBE15, 0x1007}, - {0xBE14, 0x0448}, {0xBE1E, 0x00A0}, {0xBE10, 0x8160}, {0xBE10, 0x8140}, - {0xBE00, 0x1340}, {0x0F51, 0x0010}, -}; - -/* Appears in a DDWRT code dump */ -static const struct rtl8366rb_jam_tbl_entry rtl8366rb_init_jam_ver_3[] =3D= { - {0x0000, 0x0830}, {0x0400, 0x8130}, {0x000A, 0x83ED}, {0x0431, 0x5432}, - {0x0F51, 0x0017}, {0x02F5, 0x0048}, {0x02FA, 0xFFDF}, {0x02FB, 0xFFE0}, - {0xC456, 0x0C14}, {0xC476, 0x0C14}, {0xC454, 0x3F8B}, {0xC474, 0x3F8B}, - {0xC450, 0x2071}, {0xC470, 0x2071}, {0xC451, 0x226B}, {0xC471, 0x226B}, - {0xC452, 0xA293}, {0xC472, 0xA293}, {0xC44C, 0x1585}, {0xC44C, 0x1185}, - {0xC44C, 0x1585}, {0xC46C, 0x1585}, {0xC46C, 0x1185}, {0xC46C, 0x1585}, - {0xC44C, 0x0185}, {0xC44C, 0x0181}, {0xC44C, 0x0185}, {0xC46C, 0x0185}, - {0xC46C, 0x0181}, {0xC46C, 0x0185}, {0xBE24, 0xB000}, {0xBE23, 0xFF51}, - {0xBE22, 0xDF20}, {0xBE21, 0x0140}, {0xBE20, 0x00BB}, {0xBE24, 0xB800}, - {0xBE24, 0x0000}, {0xBE24, 0x7000}, {0xBE23, 0xFF51}, {0xBE22, 0xDF60}, - {0xBE21, 0x0140}, {0xBE20, 0x0077}, {0xBE24, 0x7800}, {0xBE24, 0x0000}, - {0xBE2E, 0x7BA7}, {0xBE36, 0x1000}, {0xBE37, 0x1000}, {0x8000, 0x0001}, - {0xBE69, 0xD50F}, {0x8000, 0x0000}, {0xBE69, 0xD50F}, {0xBE6B, 0x0320}, - {0xBE77, 0x2800}, {0xBE78, 0x3C3C}, {0xBE79, 0x3C3C}, {0xBE6E, 0xE120}, - {0x8000, 0x0001}, {0xBE10, 0x8140}, {0x8000, 0x0000}, {0xBE10, 0x8140}, - {0xBE15, 0x1007}, {0xBE14, 0x0448}, {0xBE1E, 0x00A0}, {0xBE10, 0x8160}, - {0xBE10, 0x8140}, {0xBE00, 0x1340}, {0x0450, 0x0000}, {0x0401, 0x0000}, -}; - -/* Belkin F5D8235 v1, "belkin,f5d8235-v1" */ -static const struct rtl8366rb_jam_tbl_entry rtl8366rb_init_jam_f5d8235[] = =3D { - {0x0242, 0x02BF}, {0x0245, 0x02BF}, {0x0248, 0x02BF}, {0x024B, 0x02BF}, - {0x024E, 0x02BF}, {0x0251, 0x02BF}, {0x0254, 0x0A3F}, {0x0256, 0x0A3F}, - {0x0258, 0x0A3F}, {0x025A, 0x0A3F}, {0x025C, 0x0A3F}, {0x025E, 0x0A3F}, - {0x0263, 0x007C}, {0x0100, 0x0004}, {0xBE5B, 0x3500}, {0x800E, 0x200F}, - {0xBE1D, 0x0F00}, {0x8001, 0x5011}, {0x800A, 0xA2F4}, {0x800B, 0x17A3}, - {0xBE4B, 0x17A3}, {0xBE41, 0x5011}, {0xBE17, 0x2100}, {0x8000, 0x8304}, - {0xBE40, 0x8304}, {0xBE4A, 0xA2F4}, {0x800C, 0xA8D5}, {0x8014, 0x5500}, - {0x8015, 0x0004}, {0xBE4C, 0xA8D5}, {0xBE59, 0x0008}, {0xBE09, 0x0E00}, - {0xBE36, 0x1036}, {0xBE37, 0x1036}, {0x800D, 0x00FF}, {0xBE4D, 0x00FF}, -}; - -/* DGN3500, "netgear,dgn3500", "netgear,dgn3500b" */ -static const struct rtl8366rb_jam_tbl_entry rtl8366rb_init_jam_dgn3500[] = =3D { - {0x0000, 0x0830}, {0x0400, 0x8130}, {0x000A, 0x83ED}, {0x0F51, 0x0017}, - {0x02F5, 0x0048}, {0x02FA, 0xFFDF}, {0x02FB, 0xFFE0}, {0x0450, 0x0000}, - {0x0401, 0x0000}, {0x0431, 0x0960}, -}; - -/* This jam table activates "green ethernet", which means low power mode - * and is claimed to detect the cable length and not use more power than - * necessary, and the ports should enter power saving mode 10 seconds after - * a cable is disconnected. Seems to always be the same. - */ -static const struct rtl8366rb_jam_tbl_entry rtl8366rb_green_jam[] =3D { - {0xBE78, 0x323C}, {0xBE77, 0x5000}, {0xBE2E, 0x7BA7}, - {0xBE59, 0x3459}, {0xBE5A, 0x745A}, {0xBE5B, 0x785C}, - {0xBE5C, 0x785C}, {0xBE6E, 0xE120}, {0xBE79, 0x323C}, -}; - -/* Function that jams the tables in the proper registers */ -static int rtl8366rb_jam_table(const struct rtl8366rb_jam_tbl_entry *jam_t= able, - int jam_size, struct realtek_smi *smi, - bool write_dbg) -{ - u32 val; - int ret; - int i; - - for (i =3D 0; i < jam_size; i++) { - if ((jam_table[i].reg & 0xBE00) =3D=3D 0xBE00) { - ret =3D regmap_read(smi->map, - RTL8366RB_PHY_ACCESS_BUSY_REG, - &val); - if (ret) - return ret; - if (!(val & RTL8366RB_PHY_INT_BUSY)) { - ret =3D regmap_write(smi->map, - RTL8366RB_PHY_ACCESS_CTRL_REG, - RTL8366RB_PHY_CTRL_WRITE); - if (ret) - return ret; - } - } - if (write_dbg) - dev_dbg(smi->dev, "jam %04x into register %04x\n", - jam_table[i].val, - jam_table[i].reg); - ret =3D regmap_write(smi->map, - jam_table[i].reg, - jam_table[i].val); - if (ret) - return ret; - } - return 0; -} - -static int rtl8366rb_setup(struct dsa_switch *ds) -{ - struct realtek_smi *smi =3D ds->priv; - const struct rtl8366rb_jam_tbl_entry *jam_table; - struct rtl8366rb *rb; - u32 chip_ver =3D 0; - u32 chip_id =3D 0; - int jam_size; - u32 val; - int ret; - int i; - - rb =3D smi->chip_data; - - ret =3D regmap_read(smi->map, RTL8366RB_CHIP_ID_REG, &chip_id); - if (ret) { - dev_err(smi->dev, "unable to read chip id\n"); - return ret; - } - - switch (chip_id) { - case RTL8366RB_CHIP_ID_8366: - break; - default: - dev_err(smi->dev, "unknown chip id (%04x)\n", chip_id); - return -ENODEV; - } - - ret =3D regmap_read(smi->map, RTL8366RB_CHIP_VERSION_CTRL_REG, - &chip_ver); - if (ret) { - dev_err(smi->dev, "unable to read chip version\n"); - return ret; - } - - dev_info(smi->dev, "RTL%04x ver %u chip found\n", - chip_id, chip_ver & RTL8366RB_CHIP_VERSION_MASK); - - /* Do the init dance using the right jam table */ - switch (chip_ver) { - case 0: - jam_table =3D rtl8366rb_init_jam_ver_0; - jam_size =3D ARRAY_SIZE(rtl8366rb_init_jam_ver_0); - break; - case 1: - jam_table =3D rtl8366rb_init_jam_ver_1; - jam_size =3D ARRAY_SIZE(rtl8366rb_init_jam_ver_1); - break; - case 2: - jam_table =3D rtl8366rb_init_jam_ver_2; - jam_size =3D ARRAY_SIZE(rtl8366rb_init_jam_ver_2); - break; - default: - jam_table =3D rtl8366rb_init_jam_ver_3; - jam_size =3D ARRAY_SIZE(rtl8366rb_init_jam_ver_3); - break; - } - - /* Special jam tables for special routers - * TODO: are these necessary? Maintainers, please test - * without them, using just the off-the-shelf tables. - */ - if (of_machine_is_compatible("belkin,f5d8235-v1")) { - jam_table =3D rtl8366rb_init_jam_f5d8235; - jam_size =3D ARRAY_SIZE(rtl8366rb_init_jam_f5d8235); - } - if (of_machine_is_compatible("netgear,dgn3500") || - of_machine_is_compatible("netgear,dgn3500b")) { - jam_table =3D rtl8366rb_init_jam_dgn3500; - jam_size =3D ARRAY_SIZE(rtl8366rb_init_jam_dgn3500); - } - - ret =3D rtl8366rb_jam_table(jam_table, jam_size, smi, true); - if (ret) - return ret; - - /* Isolate all user ports so they can only send packets to itself and the= CPU port */ - for (i =3D 0; i < RTL8366RB_PORT_NUM_CPU; i++) { - ret =3D regmap_write(smi->map, RTL8366RB_PORT_ISO(i), - RTL8366RB_PORT_ISO_PORTS(BIT(RTL8366RB_PORT_NUM_CPU)) | - RTL8366RB_PORT_ISO_EN); - if (ret) - return ret; - } - /* CPU port can send packets to all ports */ - ret =3D regmap_write(smi->map, RTL8366RB_PORT_ISO(RTL8366RB_PORT_NUM_CPU), - RTL8366RB_PORT_ISO_PORTS(dsa_user_ports(ds)) | - RTL8366RB_PORT_ISO_EN); - if (ret) - return ret; - - /* Set up the "green ethernet" feature */ - ret =3D rtl8366rb_jam_table(rtl8366rb_green_jam, - ARRAY_SIZE(rtl8366rb_green_jam), smi, false); - if (ret) - return ret; - - ret =3D regmap_write(smi->map, - RTL8366RB_GREEN_FEATURE_REG, - (chip_ver =3D=3D 1) ? 0x0007 : 0x0003); - if (ret) - return ret; - - /* Vendor driver sets 0x240 in registers 0xc and 0xd (undocumented) */ - ret =3D regmap_write(smi->map, 0x0c, 0x240); - if (ret) - return ret; - ret =3D regmap_write(smi->map, 0x0d, 0x240); - if (ret) - return ret; - - /* Set some random MAC address */ - ret =3D rtl8366rb_set_addr(smi); - if (ret) - return ret; - - /* Enable CPU port with custom DSA tag 8899. - * - * If you set RTL8368RB_CPU_NO_TAG (bit 15) in this registers - * the custom tag is turned off. - */ - ret =3D regmap_update_bits(smi->map, RTL8368RB_CPU_CTRL_REG, - 0xFFFF, - BIT(smi->cpu_port)); - if (ret) - return ret; - - /* Make sure we default-enable the fixed CPU port */ - ret =3D regmap_update_bits(smi->map, RTL8366RB_PECR, - BIT(smi->cpu_port), - 0); - if (ret) - return ret; - - /* Set maximum packet length to 1536 bytes */ - ret =3D regmap_update_bits(smi->map, RTL8366RB_SGCR, - RTL8366RB_SGCR_MAX_LENGTH_MASK, - RTL8366RB_SGCR_MAX_LENGTH_1536); - if (ret) - return ret; - for (i =3D 0; i < RTL8366RB_NUM_PORTS; i++) - /* layer 2 size, see rtl8366rb_change_mtu() */ - rb->max_mtu[i] =3D 1532; - - /* Disable learning for all ports */ - ret =3D regmap_write(smi->map, RTL8366RB_PORT_LEARNDIS_CTRL, - RTL8366RB_PORT_ALL); - if (ret) - return ret; - - /* Enable auto ageing for all ports */ - ret =3D regmap_write(smi->map, RTL8366RB_SECURITY_CTRL, 0); - if (ret) - return ret; - - /* Port 4 setup: this enables Port 4, usually the WAN port, - * common PHY IO mode is apparently mode 0, and this is not what - * the port is initialized to. There is no explanation of the - * IO modes in the Realtek source code, if your WAN port is - * connected to something exotic such as fiber, then this might - * be worth experimenting with. - */ - ret =3D regmap_update_bits(smi->map, RTL8366RB_PMC0, - RTL8366RB_PMC0_P4_IOMODE_MASK, - 0 << RTL8366RB_PMC0_P4_IOMODE_SHIFT); - if (ret) - return ret; - - /* Accept all packets by default, we enable filtering on-demand */ - ret =3D regmap_write(smi->map, RTL8366RB_VLAN_INGRESS_CTRL1_REG, - 0); - if (ret) - return ret; - ret =3D regmap_write(smi->map, RTL8366RB_VLAN_INGRESS_CTRL2_REG, - 0); - if (ret) - return ret; - - /* Don't drop packets whose DA has not been learned */ - ret =3D regmap_update_bits(smi->map, RTL8366RB_SSCR2, - RTL8366RB_SSCR2_DROP_UNKNOWN_DA, 0); - if (ret) - return ret; - - /* Set blinking, TODO: make this configurable */ - ret =3D regmap_update_bits(smi->map, RTL8366RB_LED_BLINKRATE_REG, - RTL8366RB_LED_BLINKRATE_MASK, - RTL8366RB_LED_BLINKRATE_56MS); - if (ret) - return ret; - - /* Set up LED activity: - * Each port has 4 LEDs, we configure all ports to the same - * behaviour (no individual config) but we can set up each - * LED separately. - */ - if (smi->leds_disabled) { - /* Turn everything off */ - regmap_update_bits(smi->map, - RTL8366RB_LED_0_1_CTRL_REG, - 0x0FFF, 0); - regmap_update_bits(smi->map, - RTL8366RB_LED_2_3_CTRL_REG, - 0x0FFF, 0); - regmap_update_bits(smi->map, - RTL8366RB_INTERRUPT_CONTROL_REG, - RTL8366RB_P4_RGMII_LED, - 0); - val =3D RTL8366RB_LED_OFF; - } else { - /* TODO: make this configurable per LED */ - val =3D RTL8366RB_LED_FORCE; - } - for (i =3D 0; i < 4; i++) { - ret =3D regmap_update_bits(smi->map, - RTL8366RB_LED_CTRL_REG, - 0xf << (i * 4), - val << (i * 4)); - if (ret) - return ret; - } - - ret =3D rtl8366_reset_vlan(smi); - if (ret) - return ret; - - ret =3D rtl8366rb_setup_cascaded_irq(smi); - if (ret) - dev_info(smi->dev, "no interrupt support\n"); - - ret =3D realtek_smi_setup_mdio(smi); - if (ret) { - dev_info(smi->dev, "could not set up MDIO bus\n"); - return -ENODEV; - } - - return 0; -} - -static enum dsa_tag_protocol rtl8366_get_tag_protocol(struct dsa_switch *d= s, - int port, - enum dsa_tag_protocol mp) -{ - /* This switch uses the 4 byte protocol A Realtek DSA tag */ - return DSA_TAG_PROTO_RTL4_A; -} - -static void -rtl8366rb_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, - phy_interface_t interface, struct phy_device *phydev, - int speed, int duplex, bool tx_pause, bool rx_pause) -{ - struct realtek_smi *smi =3D ds->priv; - int ret; - - if (port !=3D smi->cpu_port) - return; - - dev_dbg(smi->dev, "MAC link up on CPU port (%d)\n", port); - - /* Force the fixed CPU port into 1Gbit mode, no autonegotiation */ - ret =3D regmap_update_bits(smi->map, RTL8366RB_MAC_FORCE_CTRL_REG, - BIT(port), BIT(port)); - if (ret) { - dev_err(smi->dev, "failed to force 1Gbit on CPU port\n"); - return; - } - - ret =3D regmap_update_bits(smi->map, RTL8366RB_PAACR2, - 0xFF00U, - RTL8366RB_PAACR_CPU_PORT << 8); - if (ret) { - dev_err(smi->dev, "failed to set PAACR on CPU port\n"); - return; - } - - /* Enable the CPU port */ - ret =3D regmap_update_bits(smi->map, RTL8366RB_PECR, BIT(port), - 0); - if (ret) { - dev_err(smi->dev, "failed to enable the CPU port\n"); - return; - } -} - -static void -rtl8366rb_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, - phy_interface_t interface) -{ - struct realtek_smi *smi =3D ds->priv; - int ret; - - if (port !=3D smi->cpu_port) - return; - - dev_dbg(smi->dev, "MAC link down on CPU port (%d)\n", port); - - /* Disable the CPU port */ - ret =3D regmap_update_bits(smi->map, RTL8366RB_PECR, BIT(port), - BIT(port)); - if (ret) { - dev_err(smi->dev, "failed to disable the CPU port\n"); - return; - } -} - -static void rb8366rb_set_port_led(struct realtek_smi *smi, - int port, bool enable) -{ - u16 val =3D enable ? 0x3f : 0; - int ret; - - if (smi->leds_disabled) - return; - - switch (port) { - case 0: - ret =3D regmap_update_bits(smi->map, - RTL8366RB_LED_0_1_CTRL_REG, - 0x3F, val); - break; - case 1: - ret =3D regmap_update_bits(smi->map, - RTL8366RB_LED_0_1_CTRL_REG, - 0x3F << RTL8366RB_LED_1_OFFSET, - val << RTL8366RB_LED_1_OFFSET); - break; - case 2: - ret =3D regmap_update_bits(smi->map, - RTL8366RB_LED_2_3_CTRL_REG, - 0x3F, val); - break; - case 3: - ret =3D regmap_update_bits(smi->map, - RTL8366RB_LED_2_3_CTRL_REG, - 0x3F << RTL8366RB_LED_3_OFFSET, - val << RTL8366RB_LED_3_OFFSET); - break; - case 4: - ret =3D regmap_update_bits(smi->map, - RTL8366RB_INTERRUPT_CONTROL_REG, - RTL8366RB_P4_RGMII_LED, - enable ? RTL8366RB_P4_RGMII_LED : 0); - break; - default: - dev_err(smi->dev, "no LED for port %d\n", port); - return; - } - if (ret) - dev_err(smi->dev, "error updating LED on port %d\n", port); -} - -static int -rtl8366rb_port_enable(struct dsa_switch *ds, int port, - struct phy_device *phy) -{ - struct realtek_smi *smi =3D ds->priv; - int ret; - - dev_dbg(smi->dev, "enable port %d\n", port); - ret =3D regmap_update_bits(smi->map, RTL8366RB_PECR, BIT(port), - 0); - if (ret) - return ret; - - rb8366rb_set_port_led(smi, port, true); - return 0; -} - -static void -rtl8366rb_port_disable(struct dsa_switch *ds, int port) -{ - struct realtek_smi *smi =3D ds->priv; - int ret; - - dev_dbg(smi->dev, "disable port %d\n", port); - ret =3D regmap_update_bits(smi->map, RTL8366RB_PECR, BIT(port), - BIT(port)); - if (ret) - return; - - rb8366rb_set_port_led(smi, port, false); -} - -static int -rtl8366rb_port_bridge_join(struct dsa_switch *ds, int port, - struct net_device *bridge) -{ - struct realtek_smi *smi =3D ds->priv; - unsigned int port_bitmap =3D 0; - int ret, i; - - /* Loop over all other ports than the current one */ - for (i =3D 0; i < RTL8366RB_PORT_NUM_CPU; i++) { - /* Current port handled last */ - if (i =3D=3D port) - continue; - /* Not on this bridge */ - if (dsa_to_port(ds, i)->bridge_dev !=3D bridge) - continue; - /* Join this port to each other port on the bridge */ - ret =3D regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(i), - RTL8366RB_PORT_ISO_PORTS(BIT(port)), - RTL8366RB_PORT_ISO_PORTS(BIT(port))); - if (ret) - dev_err(smi->dev, "failed to join port %d\n", port); - - port_bitmap |=3D BIT(i); - } - - /* Set the bits for the ports we can access */ - return regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(port), - RTL8366RB_PORT_ISO_PORTS(port_bitmap), - RTL8366RB_PORT_ISO_PORTS(port_bitmap)); -} - -static void -rtl8366rb_port_bridge_leave(struct dsa_switch *ds, int port, - struct net_device *bridge) -{ - struct realtek_smi *smi =3D ds->priv; - unsigned int port_bitmap =3D 0; - int ret, i; - - /* Loop over all other ports than this one */ - for (i =3D 0; i < RTL8366RB_PORT_NUM_CPU; i++) { - /* Current port handled last */ - if (i =3D=3D port) - continue; - /* Not on this bridge */ - if (dsa_to_port(ds, i)->bridge_dev !=3D bridge) - continue; - /* Remove this port from any other port on the bridge */ - ret =3D regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(i), - RTL8366RB_PORT_ISO_PORTS(BIT(port)), 0); - if (ret) - dev_err(smi->dev, "failed to leave port %d\n", port); - - port_bitmap |=3D BIT(i); - } - - /* Clear the bits for the ports we can not access, leave ourselves */ - regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(port), - RTL8366RB_PORT_ISO_PORTS(port_bitmap), 0); -} - -/** - * rtl8366rb_drop_untagged() - make the switch drop untagged and C-tagged = frames - * @smi: SMI state container - * @port: the port to drop untagged and C-tagged frames on - * @drop: whether to drop or pass untagged and C-tagged frames - */ -static int rtl8366rb_drop_untagged(struct realtek_smi *smi, int port, bool= drop) -{ - return regmap_update_bits(smi->map, RTL8366RB_VLAN_INGRESS_CTRL1_REG, - RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port), - drop ? RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port) : 0); -} - -static int rtl8366rb_vlan_filtering(struct dsa_switch *ds, int port, - bool vlan_filtering, - struct netlink_ext_ack *extack) -{ - struct realtek_smi *smi =3D ds->priv; - struct rtl8366rb *rb; - int ret; - - rb =3D smi->chip_data; - - dev_dbg(smi->dev, "port %d: %s VLAN filtering\n", port, - vlan_filtering ? "enable" : "disable"); - - /* If the port is not in the member set, the frame will be dropped */ - ret =3D regmap_update_bits(smi->map, RTL8366RB_VLAN_INGRESS_CTRL2_REG, - BIT(port), vlan_filtering ? BIT(port) : 0); - if (ret) - return ret; - - /* If VLAN filtering is enabled and PVID is also enabled, we must - * not drop any untagged or C-tagged frames. If we turn off VLAN - * filtering on a port, we need to accept any frames. - */ - if (vlan_filtering) - ret =3D rtl8366rb_drop_untagged(smi, port, !rb->pvid_enabled[port]); - else - ret =3D rtl8366rb_drop_untagged(smi, port, false); - - return ret; -} - -static int -rtl8366rb_port_pre_bridge_flags(struct dsa_switch *ds, int port, - struct switchdev_brport_flags flags, - struct netlink_ext_ack *extack) -{ - /* We support enabling/disabling learning */ - if (flags.mask & ~(BR_LEARNING)) - return -EINVAL; - - return 0; -} - -static int -rtl8366rb_port_bridge_flags(struct dsa_switch *ds, int port, - struct switchdev_brport_flags flags, - struct netlink_ext_ack *extack) -{ - struct realtek_smi *smi =3D ds->priv; - int ret; - - if (flags.mask & BR_LEARNING) { - ret =3D regmap_update_bits(smi->map, RTL8366RB_PORT_LEARNDIS_CTRL, - BIT(port), - (flags.val & BR_LEARNING) ? 0 : BIT(port)); - if (ret) - return ret; - } - - return 0; -} - -static void -rtl8366rb_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) -{ - struct realtek_smi *smi =3D ds->priv; - u32 val; - int i; - - switch (state) { - case BR_STATE_DISABLED: - val =3D RTL8366RB_STP_STATE_DISABLED; - break; - case BR_STATE_BLOCKING: - case BR_STATE_LISTENING: - val =3D RTL8366RB_STP_STATE_BLOCKING; - break; - case BR_STATE_LEARNING: - val =3D RTL8366RB_STP_STATE_LEARNING; - break; - case BR_STATE_FORWARDING: - val =3D RTL8366RB_STP_STATE_FORWARDING; - break; - default: - dev_err(smi->dev, "unknown bridge state requested\n"); - return; - } - - /* Set the same status for the port on all the FIDs */ - for (i =3D 0; i < RTL8366RB_NUM_FIDS; i++) { - regmap_update_bits(smi->map, RTL8366RB_STP_STATE_BASE + i, - RTL8366RB_STP_STATE_MASK(port), - RTL8366RB_STP_STATE(port, val)); - } -} - -static void -rtl8366rb_port_fast_age(struct dsa_switch *ds, int port) -{ - struct realtek_smi *smi =3D ds->priv; - - /* This will age out any learned L2 entries */ - regmap_update_bits(smi->map, RTL8366RB_SECURITY_CTRL, - BIT(port), BIT(port)); - /* Restore the normal state of things */ - regmap_update_bits(smi->map, RTL8366RB_SECURITY_CTRL, - BIT(port), 0); -} - -static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_m= tu) -{ - struct realtek_smi *smi =3D ds->priv; - struct rtl8366rb *rb; - unsigned int max_mtu; - u32 len; - int i; - - /* Cache the per-port MTU setting */ - rb =3D smi->chip_data; - rb->max_mtu[port] =3D new_mtu; - - /* Roof out the MTU for the entire switch to the greatest - * common denominator: the biggest set for any one port will - * be the biggest MTU for the switch. - * - * The first setting, 1522 bytes, is max IP packet 1500 bytes, - * plus ethernet header, 1518 bytes, plus CPU tag, 4 bytes. - * This function should consider the parameter an SDU, so the - * MTU passed for this setting is 1518 bytes. The same logic - * of subtracting the DSA tag of 4 bytes apply to the other - * settings. - */ - max_mtu =3D 1518; - for (i =3D 0; i < RTL8366RB_NUM_PORTS; i++) { - if (rb->max_mtu[i] > max_mtu) - max_mtu =3D rb->max_mtu[i]; - } - if (max_mtu <=3D 1518) - len =3D RTL8366RB_SGCR_MAX_LENGTH_1522; - else if (max_mtu > 1518 && max_mtu <=3D 1532) - len =3D RTL8366RB_SGCR_MAX_LENGTH_1536; - else if (max_mtu > 1532 && max_mtu <=3D 1548) - len =3D RTL8366RB_SGCR_MAX_LENGTH_1552; - else - len =3D RTL8366RB_SGCR_MAX_LENGTH_16000; - - return regmap_update_bits(smi->map, RTL8366RB_SGCR, - RTL8366RB_SGCR_MAX_LENGTH_MASK, - len); -} - -static int rtl8366rb_max_mtu(struct dsa_switch *ds, int port) -{ - /* The max MTU is 16000 bytes, so we subtract the CPU tag - * and the max presented to the system is 15996 bytes. - */ - return 15996; -} - -static int rtl8366rb_get_vlan_4k(struct realtek_smi *smi, u32 vid, - struct rtl8366_vlan_4k *vlan4k) -{ - u32 data[3]; - int ret; - int i; - - memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); - - if (vid >=3D RTL8366RB_NUM_VIDS) - return -EINVAL; - - /* write VID */ - ret =3D regmap_write(smi->map, RTL8366RB_VLAN_TABLE_WRITE_BASE, - vid & RTL8366RB_VLAN_VID_MASK); - if (ret) - return ret; - - /* write table access control word */ - ret =3D regmap_write(smi->map, RTL8366RB_TABLE_ACCESS_CTRL_REG, - RTL8366RB_TABLE_VLAN_READ_CTRL); - if (ret) - return ret; - - for (i =3D 0; i < 3; i++) { - ret =3D regmap_read(smi->map, - RTL8366RB_VLAN_TABLE_READ_BASE + i, - &data[i]); - if (ret) - return ret; - } - - vlan4k->vid =3D vid; - vlan4k->untag =3D (data[1] >> RTL8366RB_VLAN_UNTAG_SHIFT) & - RTL8366RB_VLAN_UNTAG_MASK; - vlan4k->member =3D data[1] & RTL8366RB_VLAN_MEMBER_MASK; - vlan4k->fid =3D data[2] & RTL8366RB_VLAN_FID_MASK; - - return 0; -} - -static int rtl8366rb_set_vlan_4k(struct realtek_smi *smi, - const struct rtl8366_vlan_4k *vlan4k) -{ - u32 data[3]; - int ret; - int i; - - if (vlan4k->vid >=3D RTL8366RB_NUM_VIDS || - vlan4k->member > RTL8366RB_VLAN_MEMBER_MASK || - vlan4k->untag > RTL8366RB_VLAN_UNTAG_MASK || - vlan4k->fid > RTL8366RB_FIDMAX) - return -EINVAL; - - data[0] =3D vlan4k->vid & RTL8366RB_VLAN_VID_MASK; - data[1] =3D (vlan4k->member & RTL8366RB_VLAN_MEMBER_MASK) | - ((vlan4k->untag & RTL8366RB_VLAN_UNTAG_MASK) << - RTL8366RB_VLAN_UNTAG_SHIFT); - data[2] =3D vlan4k->fid & RTL8366RB_VLAN_FID_MASK; - - for (i =3D 0; i < 3; i++) { - ret =3D regmap_write(smi->map, - RTL8366RB_VLAN_TABLE_WRITE_BASE + i, - data[i]); - if (ret) - return ret; - } - - /* write table access control word */ - ret =3D regmap_write(smi->map, RTL8366RB_TABLE_ACCESS_CTRL_REG, - RTL8366RB_TABLE_VLAN_WRITE_CTRL); - - return ret; -} - -static int rtl8366rb_get_vlan_mc(struct realtek_smi *smi, u32 index, - struct rtl8366_vlan_mc *vlanmc) -{ - u32 data[3]; - int ret; - int i; - - memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); - - if (index >=3D RTL8366RB_NUM_VLANS) - return -EINVAL; - - for (i =3D 0; i < 3; i++) { - ret =3D regmap_read(smi->map, - RTL8366RB_VLAN_MC_BASE(index) + i, - &data[i]); - if (ret) - return ret; - } - - vlanmc->vid =3D data[0] & RTL8366RB_VLAN_VID_MASK; - vlanmc->priority =3D (data[0] >> RTL8366RB_VLAN_PRIORITY_SHIFT) & - RTL8366RB_VLAN_PRIORITY_MASK; - vlanmc->untag =3D (data[1] >> RTL8366RB_VLAN_UNTAG_SHIFT) & - RTL8366RB_VLAN_UNTAG_MASK; - vlanmc->member =3D data[1] & RTL8366RB_VLAN_MEMBER_MASK; - vlanmc->fid =3D data[2] & RTL8366RB_VLAN_FID_MASK; - - return 0; -} - -static int rtl8366rb_set_vlan_mc(struct realtek_smi *smi, u32 index, - const struct rtl8366_vlan_mc *vlanmc) -{ - u32 data[3]; - int ret; - int i; - - if (index >=3D RTL8366RB_NUM_VLANS || - vlanmc->vid >=3D RTL8366RB_NUM_VIDS || - vlanmc->priority > RTL8366RB_PRIORITYMAX || - vlanmc->member > RTL8366RB_VLAN_MEMBER_MASK || - vlanmc->untag > RTL8366RB_VLAN_UNTAG_MASK || - vlanmc->fid > RTL8366RB_FIDMAX) - return -EINVAL; - - data[0] =3D (vlanmc->vid & RTL8366RB_VLAN_VID_MASK) | - ((vlanmc->priority & RTL8366RB_VLAN_PRIORITY_MASK) << - RTL8366RB_VLAN_PRIORITY_SHIFT); - data[1] =3D (vlanmc->member & RTL8366RB_VLAN_MEMBER_MASK) | - ((vlanmc->untag & RTL8366RB_VLAN_UNTAG_MASK) << - RTL8366RB_VLAN_UNTAG_SHIFT); - data[2] =3D vlanmc->fid & RTL8366RB_VLAN_FID_MASK; - - for (i =3D 0; i < 3; i++) { - ret =3D regmap_write(smi->map, - RTL8366RB_VLAN_MC_BASE(index) + i, - data[i]); - if (ret) - return ret; - } - - return 0; -} - -static int rtl8366rb_get_mc_index(struct realtek_smi *smi, int port, int *= val) -{ - u32 data; - int ret; - - if (port >=3D smi->num_ports) - return -EINVAL; - - ret =3D regmap_read(smi->map, RTL8366RB_PORT_VLAN_CTRL_REG(port), - &data); - if (ret) - return ret; - - *val =3D (data >> RTL8366RB_PORT_VLAN_CTRL_SHIFT(port)) & - RTL8366RB_PORT_VLAN_CTRL_MASK; - - return 0; -} - -static int rtl8366rb_set_mc_index(struct realtek_smi *smi, int port, int i= ndex) -{ - struct rtl8366rb *rb; - bool pvid_enabled; - int ret; - - rb =3D smi->chip_data; - pvid_enabled =3D !!index; - - if (port >=3D smi->num_ports || index >=3D RTL8366RB_NUM_VLANS) - return -EINVAL; - - ret =3D regmap_update_bits(smi->map, RTL8366RB_PORT_VLAN_CTRL_REG(port), - RTL8366RB_PORT_VLAN_CTRL_MASK << - RTL8366RB_PORT_VLAN_CTRL_SHIFT(port), - (index & RTL8366RB_PORT_VLAN_CTRL_MASK) << - RTL8366RB_PORT_VLAN_CTRL_SHIFT(port)); - if (ret) - return ret; - - rb->pvid_enabled[port] =3D pvid_enabled; - - /* If VLAN filtering is enabled and PVID is also enabled, we must - * not drop any untagged or C-tagged frames. Make sure to update the - * filtering setting. - */ - if (dsa_port_is_vlan_filtering(dsa_to_port(smi->ds, port))) - ret =3D rtl8366rb_drop_untagged(smi, port, !pvid_enabled); - - return ret; -} - -static bool rtl8366rb_is_vlan_valid(struct realtek_smi *smi, unsigned int = vlan) -{ - unsigned int max =3D RTL8366RB_NUM_VLANS - 1; - - if (smi->vlan4k_enabled) - max =3D RTL8366RB_NUM_VIDS - 1; - - if (vlan > max) - return false; - - return true; -} - -static int rtl8366rb_enable_vlan(struct realtek_smi *smi, bool enable) -{ - dev_dbg(smi->dev, "%s VLAN\n", enable ? "enable" : "disable"); - return regmap_update_bits(smi->map, - RTL8366RB_SGCR, RTL8366RB_SGCR_EN_VLAN, - enable ? RTL8366RB_SGCR_EN_VLAN : 0); -} - -static int rtl8366rb_enable_vlan4k(struct realtek_smi *smi, bool enable) -{ - dev_dbg(smi->dev, "%s VLAN 4k\n", enable ? "enable" : "disable"); - return regmap_update_bits(smi->map, RTL8366RB_SGCR, - RTL8366RB_SGCR_EN_VLAN_4KTB, - enable ? RTL8366RB_SGCR_EN_VLAN_4KTB : 0); -} - -static int rtl8366rb_phy_read(struct realtek_smi *smi, int phy, int regnum) -{ - u32 val; - u32 reg; - int ret; - - if (phy > RTL8366RB_PHY_NO_MAX) - return -EINVAL; - - ret =3D regmap_write(smi->map, RTL8366RB_PHY_ACCESS_CTRL_REG, - RTL8366RB_PHY_CTRL_READ); - if (ret) - return ret; - - reg =3D 0x8000 | (1 << (phy + RTL8366RB_PHY_NO_OFFSET)) | regnum; - - ret =3D regmap_write(smi->map, reg, 0); - if (ret) { - dev_err(smi->dev, - "failed to write PHY%d reg %04x @ %04x, ret %d\n", - phy, regnum, reg, ret); - return ret; - } - - ret =3D regmap_read(smi->map, RTL8366RB_PHY_ACCESS_DATA_REG, &val); - if (ret) - return ret; - - dev_dbg(smi->dev, "read PHY%d register 0x%04x @ %08x, val <- %04x\n", - phy, regnum, reg, val); - - return val; -} - -static int rtl8366rb_phy_write(struct realtek_smi *smi, int phy, int regnu= m, - u16 val) -{ - u32 reg; - int ret; - - if (phy > RTL8366RB_PHY_NO_MAX) - return -EINVAL; - - ret =3D regmap_write(smi->map, RTL8366RB_PHY_ACCESS_CTRL_REG, - RTL8366RB_PHY_CTRL_WRITE); - if (ret) - return ret; - - reg =3D 0x8000 | (1 << (phy + RTL8366RB_PHY_NO_OFFSET)) | regnum; - - dev_dbg(smi->dev, "write PHY%d register 0x%04x @ %04x, val -> %04x\n", - phy, regnum, reg, val); - - ret =3D regmap_write(smi->map, reg, val); - if (ret) - return ret; - - return 0; -} - -static int rtl8366rb_reset_chip(struct realtek_smi *smi) -{ - int timeout =3D 10; - u32 val; - int ret; - - realtek_smi_write_reg_noack(smi, RTL8366RB_RESET_CTRL_REG, - RTL8366RB_CHIP_CTRL_RESET_HW); - do { - usleep_range(20000, 25000); - ret =3D regmap_read(smi->map, RTL8366RB_RESET_CTRL_REG, &val); - if (ret) - return ret; - - if (!(val & RTL8366RB_CHIP_CTRL_RESET_HW)) - break; - } while (--timeout); - - if (!timeout) { - dev_err(smi->dev, "timeout waiting for the switch to reset\n"); - return -EIO; - } - - return 0; -} - -static int rtl8366rb_detect(struct realtek_smi *smi) -{ - struct device *dev =3D smi->dev; - int ret; - u32 val; - - /* Detect device */ - ret =3D regmap_read(smi->map, 0x5c, &val); - if (ret) { - dev_err(dev, "can't get chip ID (%d)\n", ret); - return ret; - } - - switch (val) { - case 0x6027: - dev_info(dev, "found an RTL8366S switch\n"); - dev_err(dev, "this switch is not yet supported, submit patches!\n"); - return -ENODEV; - case 0x5937: - dev_info(dev, "found an RTL8366RB switch\n"); - smi->cpu_port =3D RTL8366RB_PORT_NUM_CPU; - smi->num_ports =3D RTL8366RB_NUM_PORTS; - smi->num_vlan_mc =3D RTL8366RB_NUM_VLANS; - smi->mib_counters =3D rtl8366rb_mib_counters; - smi->num_mib_counters =3D ARRAY_SIZE(rtl8366rb_mib_counters); - break; - default: - dev_info(dev, "found an Unknown Realtek switch (id=3D0x%04x)\n", - val); - break; - } - - ret =3D rtl8366rb_reset_chip(smi); - if (ret) - return ret; - - return 0; -} - -static const struct dsa_switch_ops rtl8366rb_switch_ops =3D { - .get_tag_protocol =3D rtl8366_get_tag_protocol, - .setup =3D rtl8366rb_setup, - .phylink_mac_link_up =3D rtl8366rb_mac_link_up, - .phylink_mac_link_down =3D rtl8366rb_mac_link_down, - .get_strings =3D rtl8366_get_strings, - .get_ethtool_stats =3D rtl8366_get_ethtool_stats, - .get_sset_count =3D rtl8366_get_sset_count, - .port_bridge_join =3D rtl8366rb_port_bridge_join, - .port_bridge_leave =3D rtl8366rb_port_bridge_leave, - .port_vlan_filtering =3D rtl8366rb_vlan_filtering, - .port_vlan_add =3D rtl8366_vlan_add, - .port_vlan_del =3D rtl8366_vlan_del, - .port_enable =3D rtl8366rb_port_enable, - .port_disable =3D rtl8366rb_port_disable, - .port_pre_bridge_flags =3D rtl8366rb_port_pre_bridge_flags, - .port_bridge_flags =3D rtl8366rb_port_bridge_flags, - .port_stp_state_set =3D rtl8366rb_port_stp_state_set, - .port_fast_age =3D rtl8366rb_port_fast_age, - .port_change_mtu =3D rtl8366rb_change_mtu, - .port_max_mtu =3D rtl8366rb_max_mtu, -}; - -static const struct realtek_smi_ops rtl8366rb_smi_ops =3D { - .detect =3D rtl8366rb_detect, - .get_vlan_mc =3D rtl8366rb_get_vlan_mc, - .set_vlan_mc =3D rtl8366rb_set_vlan_mc, - .get_vlan_4k =3D rtl8366rb_get_vlan_4k, - .set_vlan_4k =3D rtl8366rb_set_vlan_4k, - .get_mc_index =3D rtl8366rb_get_mc_index, - .set_mc_index =3D rtl8366rb_set_mc_index, - .get_mib_counter =3D rtl8366rb_get_mib_counter, - .is_vlan_valid =3D rtl8366rb_is_vlan_valid, - .enable_vlan =3D rtl8366rb_enable_vlan, - .enable_vlan4k =3D rtl8366rb_enable_vlan4k, - .phy_read =3D rtl8366rb_phy_read, - .phy_write =3D rtl8366rb_phy_write, -}; - -const struct realtek_smi_variant rtl8366rb_variant =3D { - .ds_ops =3D &rtl8366rb_switch_ops, - .ops =3D &rtl8366rb_smi_ops, - .clk_delay =3D 10, - .cmd_read =3D 0xa9, - .cmd_write =3D 0xa8, - .chip_data_sz =3D sizeof(struct rtl8366rb), -}; -EXPORT_SYMBOL_GPL(rtl8366rb_variant); diff --git a/drivers/net/ethernet/8390/mcf8390.c b/drivers/net/ethernet/839= 0/mcf8390.c index e320cccba61a..90cd7bdf06f5 100644 --- a/drivers/net/ethernet/8390/mcf8390.c +++ b/drivers/net/ethernet/8390/mcf8390.c @@ -405,12 +405,12 @@ static int mcf8390_init(struct net_device *dev) static int mcf8390_probe(struct platform_device *pdev) { struct net_device *dev; - struct resource *mem, *irq; + struct resource *mem; resource_size_t msize; - int ret; + int ret, irq; =20 - irq =3D platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (irq =3D=3D NULL) { + irq =3D platform_get_irq(pdev, 0); + if (irq < 0) { dev_err(&pdev->dev, "no IRQ specified?\n"); return -ENXIO; } @@ -433,7 +433,7 @@ static int mcf8390_probe(struct platform_device *pdev) SET_NETDEV_DEV(dev, &pdev->dev); platform_set_drvdata(pdev, dev); =20 - dev->irq =3D irq->start; + dev->irq =3D irq; dev->base_addr =3D mem->start; =20 ret =3D mcf8390_init(dev); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c b/drivers/net/et= hernet/broadcom/bnxt/bnxt_ptp.c index 8388be119f9a..4eca32a29c9b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c @@ -329,7 +329,7 @@ static int bnxt_ptp_enable(struct ptp_clock_info *ptp_i= nfo, struct bnxt_ptp_cfg *ptp =3D container_of(ptp_info, struct bnxt_ptp_cfg, ptp_info); struct bnxt *bp =3D ptp->bp; - u8 pin_id; + int pin_id; int rc; =20 switch (rq->type) { @@ -337,6 +337,8 @@ static int bnxt_ptp_enable(struct ptp_clock_info *ptp_i= nfo, /* Configure an External PPS IN */ pin_id =3D ptp_find_pin(ptp->ptp_clock, PTP_PF_EXTTS, rq->extts.index); + if (!TSIO_PIN_VALID(pin_id)) + return -EOPNOTSUPP; if (!on) break; rc =3D bnxt_ptp_cfg_pin(bp, pin_id, BNXT_PPS_PIN_PPS_IN); @@ -350,6 +352,8 @@ static int bnxt_ptp_enable(struct ptp_clock_info *ptp_i= nfo, /* Configure a Periodic PPS OUT */ pin_id =3D ptp_find_pin(ptp->ptp_clock, PTP_PF_PEROUT, rq->perout.index); + if (!TSIO_PIN_VALID(pin_id)) + return -EOPNOTSUPP; if (!on) break; =20 diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h b/drivers/net/et= hernet/broadcom/bnxt/bnxt_ptp.h index 7c528e1f8713..8205140db829 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h @@ -31,7 +31,7 @@ struct pps_pin { u8 state; }; =20 -#define TSIO_PIN_VALID(pin) ((pin) < (BNXT_MAX_TSIO_PINS)) +#define TSIO_PIN_VALID(pin) ((pin) >=3D 0 && (pin) < (BNXT_MAX_TSIO_PINS)) =20 #define EVENT_DATA2_PPS_EVENT_TYPE(data2) \ ((data2) & ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_DATA2_EVENT_TYPE) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/e= thernet/broadcom/genet/bcmgenet.c index 2da804f84b48..bd5998012a87 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -76,7 +76,7 @@ static inline void bcmgenet_writel(u32 value, void __iome= m *offset) if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) __raw_writel(value, offset); else - writel_relaxed(value, offset); + writel(value, offset); } =20 static inline u32 bcmgenet_readl(void __iomem *offset) @@ -84,7 +84,7 @@ static inline u32 bcmgenet_readl(void __iomem *offset) if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) return __raw_readl(offset); else - return readl_relaxed(offset); + return readl(offset); } =20 static inline void dmadesc_set_length_status(struct bcmgenet_priv *priv, diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers= /net/ethernet/freescale/enetc/enetc_ethtool.c index 910b9f722504..d62c188c8748 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c @@ -672,7 +672,10 @@ static int enetc_get_ts_info(struct net_device *ndev, #ifdef CONFIG_FSL_ENETC_PTP_CLOCK info->so_timestamping =3D SOF_TIMESTAMPING_TX_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE | - SOF_TIMESTAMPING_RAW_HARDWARE; + SOF_TIMESTAMPING_RAW_HARDWARE | + SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE; =20 info->tx_types =3D (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON) | diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net= /ethernet/freescale/enetc/enetc_qos.c index 0536d2c76fbc..d779dde522c8 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c @@ -45,6 +45,7 @@ void enetc_sched_speed_set(struct enetc_ndev_priv *priv, = int speed) | pspeed); } =20 +#define ENETC_QOS_ALIGN 64 static int enetc_setup_taprio(struct net_device *ndev, struct tc_taprio_qopt_offload *admin_conf) { @@ -52,10 +53,11 @@ static int enetc_setup_taprio(struct net_device *ndev, struct enetc_cbd cbd =3D {.cmd =3D 0}; struct tgs_gcl_conf *gcl_config; struct tgs_gcl_data *gcl_data; + dma_addr_t dma, dma_align; struct gce *gce; - dma_addr_t dma; u16 data_size; u16 gcl_len; + void *tmp; u32 tge; int err; int i; @@ -82,9 +84,16 @@ static int enetc_setup_taprio(struct net_device *ndev, gcl_config =3D &cbd.gcl_conf; =20 data_size =3D struct_size(gcl_data, entry, gcl_len); - gcl_data =3D kzalloc(data_size, __GFP_DMA | GFP_KERNEL); - if (!gcl_data) + tmp =3D dma_alloc_coherent(&priv->si->pdev->dev, + data_size + ENETC_QOS_ALIGN, + &dma, GFP_KERNEL); + if (!tmp) { + dev_err(&priv->si->pdev->dev, + "DMA mapping of taprio gate list failed!\n"); return -ENOMEM; + } + dma_align =3D ALIGN(dma, ENETC_QOS_ALIGN); + gcl_data =3D (struct tgs_gcl_data *)PTR_ALIGN(tmp, ENETC_QOS_ALIGN); =20 gce =3D (struct gce *)(gcl_data + 1); =20 @@ -110,16 +119,8 @@ static int enetc_setup_taprio(struct net_device *ndev, cbd.length =3D cpu_to_le16(data_size); cbd.status_flags =3D 0; =20 - dma =3D dma_map_single(&priv->si->pdev->dev, gcl_data, - data_size, DMA_TO_DEVICE); - if (dma_mapping_error(&priv->si->pdev->dev, dma)) { - netdev_err(priv->si->ndev, "DMA mapping failed!\n"); - kfree(gcl_data); - return -ENOMEM; - } - - cbd.addr[0] =3D cpu_to_le32(lower_32_bits(dma)); - cbd.addr[1] =3D cpu_to_le32(upper_32_bits(dma)); + cbd.addr[0] =3D cpu_to_le32(lower_32_bits(dma_align)); + cbd.addr[1] =3D cpu_to_le32(upper_32_bits(dma_align)); cbd.cls =3D BDCR_CMD_PORT_GCL; cbd.status_flags =3D 0; =20 @@ -132,8 +133,8 @@ static int enetc_setup_taprio(struct net_device *ndev, ENETC_QBV_PTGCR_OFFSET, tge & (~ENETC_QBV_TGE)); =20 - dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE); - kfree(gcl_data); + dma_free_coherent(&priv->si->pdev->dev, data_size + ENETC_QOS_ALIGN, + tmp, dma); =20 return err; } @@ -463,8 +464,9 @@ static int enetc_streamid_hw_set(struct enetc_ndev_priv= *priv, struct enetc_cbd cbd =3D {.cmd =3D 0}; struct streamid_data *si_data; struct streamid_conf *si_conf; + dma_addr_t dma, dma_align; u16 data_size; - dma_addr_t dma; + void *tmp; int port; int err; =20 @@ -485,21 +487,20 @@ static int enetc_streamid_hw_set(struct enetc_ndev_pr= iv *priv, cbd.status_flags =3D 0; =20 data_size =3D sizeof(struct streamid_data); - si_data =3D kzalloc(data_size, __GFP_DMA | GFP_KERNEL); - if (!si_data) + tmp =3D dma_alloc_coherent(&priv->si->pdev->dev, + data_size + ENETC_QOS_ALIGN, + &dma, GFP_KERNEL); + if (!tmp) { + dev_err(&priv->si->pdev->dev, + "DMA mapping of stream identify failed!\n"); return -ENOMEM; - cbd.length =3D cpu_to_le16(data_size); - - dma =3D dma_map_single(&priv->si->pdev->dev, si_data, - data_size, DMA_FROM_DEVICE); - if (dma_mapping_error(&priv->si->pdev->dev, dma)) { - netdev_err(priv->si->ndev, "DMA mapping failed!\n"); - err =3D -ENOMEM; - goto out; } + dma_align =3D ALIGN(dma, ENETC_QOS_ALIGN); + si_data =3D (struct streamid_data *)PTR_ALIGN(tmp, ENETC_QOS_ALIGN); =20 - cbd.addr[0] =3D cpu_to_le32(lower_32_bits(dma)); - cbd.addr[1] =3D cpu_to_le32(upper_32_bits(dma)); + cbd.length =3D cpu_to_le16(data_size); + cbd.addr[0] =3D cpu_to_le32(lower_32_bits(dma_align)); + cbd.addr[1] =3D cpu_to_le32(upper_32_bits(dma_align)); eth_broadcast_addr(si_data->dmac); si_data->vid_vidm_tg =3D (ENETC_CBDR_SID_VID_MASK + ((0x3 << 14) | ENETC_CBDR_SID_VIDM)); @@ -539,8 +540,8 @@ static int enetc_streamid_hw_set(struct enetc_ndev_priv= *priv, =20 cbd.length =3D cpu_to_le16(data_size); =20 - cbd.addr[0] =3D cpu_to_le32(lower_32_bits(dma)); - cbd.addr[1] =3D cpu_to_le32(upper_32_bits(dma)); + cbd.addr[0] =3D cpu_to_le32(lower_32_bits(dma_align)); + cbd.addr[1] =3D cpu_to_le32(upper_32_bits(dma_align)); =20 /* VIDM default to be 1. * VID Match. If set (b1) then the VID must match, otherwise @@ -561,10 +562,8 @@ static int enetc_streamid_hw_set(struct enetc_ndev_pri= v *priv, =20 err =3D enetc_send_cmd(priv->si, &cbd); out: - if (!dma_mapping_error(&priv->si->pdev->dev, dma)) - dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_FROM_DEVICE); - - kfree(si_data); + dma_free_coherent(&priv->si->pdev->dev, data_size + ENETC_QOS_ALIGN, + tmp, dma); =20 return err; } @@ -633,8 +632,9 @@ static int enetc_streamcounter_hw_get(struct enetc_ndev= _priv *priv, { struct enetc_cbd cbd =3D { .cmd =3D 2 }; struct sfi_counter_data *data_buf; - dma_addr_t dma; + dma_addr_t dma, dma_align; u16 data_size; + void *tmp; int err; =20 cbd.index =3D cpu_to_le16((u16)index); @@ -643,19 +643,19 @@ static int enetc_streamcounter_hw_get(struct enetc_nd= ev_priv *priv, cbd.status_flags =3D 0; =20 data_size =3D sizeof(struct sfi_counter_data); - data_buf =3D kzalloc(data_size, __GFP_DMA | GFP_KERNEL); - if (!data_buf) + tmp =3D dma_alloc_coherent(&priv->si->pdev->dev, + data_size + ENETC_QOS_ALIGN, + &dma, GFP_KERNEL); + if (!tmp) { + dev_err(&priv->si->pdev->dev, + "DMA mapping of stream counter failed!\n"); return -ENOMEM; - - dma =3D dma_map_single(&priv->si->pdev->dev, data_buf, - data_size, DMA_FROM_DEVICE); - if (dma_mapping_error(&priv->si->pdev->dev, dma)) { - netdev_err(priv->si->ndev, "DMA mapping failed!\n"); - err =3D -ENOMEM; - goto exit; } - cbd.addr[0] =3D cpu_to_le32(lower_32_bits(dma)); - cbd.addr[1] =3D cpu_to_le32(upper_32_bits(dma)); + dma_align =3D ALIGN(dma, ENETC_QOS_ALIGN); + data_buf =3D (struct sfi_counter_data *)PTR_ALIGN(tmp, ENETC_QOS_ALIGN); + + cbd.addr[0] =3D cpu_to_le32(lower_32_bits(dma_align)); + cbd.addr[1] =3D cpu_to_le32(upper_32_bits(dma_align)); =20 cbd.length =3D cpu_to_le16(data_size); =20 @@ -684,7 +684,9 @@ static int enetc_streamcounter_hw_get(struct enetc_ndev= _priv *priv, data_buf->flow_meter_dropl; =20 exit: - kfree(data_buf); + dma_free_coherent(&priv->si->pdev->dev, data_size + ENETC_QOS_ALIGN, + tmp, dma); + return err; } =20 @@ -723,9 +725,10 @@ static int enetc_streamgate_hw_set(struct enetc_ndev_p= riv *priv, struct sgcl_conf *sgcl_config; struct sgcl_data *sgcl_data; struct sgce *sgce; - dma_addr_t dma; + dma_addr_t dma, dma_align; u16 data_size; int err, i; + void *tmp; u64 now; =20 cbd.index =3D cpu_to_le16(sgi->index); @@ -772,24 +775,20 @@ static int enetc_streamgate_hw_set(struct enetc_ndev_= priv *priv, sgcl_config->acl_len =3D (sgi->num_entries - 1) & 0x3; =20 data_size =3D struct_size(sgcl_data, sgcl, sgi->num_entries); - - sgcl_data =3D kzalloc(data_size, __GFP_DMA | GFP_KERNEL); - if (!sgcl_data) - return -ENOMEM; - - cbd.length =3D cpu_to_le16(data_size); - - dma =3D dma_map_single(&priv->si->pdev->dev, - sgcl_data, data_size, - DMA_FROM_DEVICE); - if (dma_mapping_error(&priv->si->pdev->dev, dma)) { - netdev_err(priv->si->ndev, "DMA mapping failed!\n"); - kfree(sgcl_data); + tmp =3D dma_alloc_coherent(&priv->si->pdev->dev, + data_size + ENETC_QOS_ALIGN, + &dma, GFP_KERNEL); + if (!tmp) { + dev_err(&priv->si->pdev->dev, + "DMA mapping of stream counter failed!\n"); return -ENOMEM; } + dma_align =3D ALIGN(dma, ENETC_QOS_ALIGN); + sgcl_data =3D (struct sgcl_data *)PTR_ALIGN(tmp, ENETC_QOS_ALIGN); =20 - cbd.addr[0] =3D cpu_to_le32(lower_32_bits(dma)); - cbd.addr[1] =3D cpu_to_le32(upper_32_bits(dma)); + cbd.length =3D cpu_to_le16(data_size); + cbd.addr[0] =3D cpu_to_le32(lower_32_bits(dma_align)); + cbd.addr[1] =3D cpu_to_le32(upper_32_bits(dma_align)); =20 sgce =3D &sgcl_data->sgcl[0]; =20 @@ -844,7 +843,8 @@ static int enetc_streamgate_hw_set(struct enetc_ndev_pr= iv *priv, err =3D enetc_send_cmd(priv->si, &cbd); =20 exit: - kfree(sgcl_data); + dma_free_coherent(&priv->si->pdev->dev, data_size + ENETC_QOS_ALIGN, + tmp, dma); =20 return err; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethe= rnet/hisilicon/hns3/hnae3.h index 63f5abcc6bf4..8184a954f648 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -536,6 +536,8 @@ struct hnae3_ae_dev { * Get 1588 rx hwstamp * get_ts_info * Get phc info + * clean_vf_config + * Clean residual vf info after disable sriov */ struct hnae3_ae_ops { int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev); @@ -729,6 +731,7 @@ struct hnae3_ae_ops { struct ethtool_ts_info *info); int (*get_link_diagnosis_info)(struct hnae3_handle *handle, u32 *status_code); + void (*clean_vf_config)(struct hnae3_ae_dev *ae_dev, int num_vfs); }; =20 struct hnae3_dcb_ops { @@ -841,6 +844,7 @@ struct hnae3_handle { struct dentry *hnae3_dbgfs; /* protects concurrent contention between debugfs commands */ struct mutex dbgfs_lock; + char **dbgfs_buf; =20 /* Network interface message level enabled bits */ u32 msg_enable; @@ -861,6 +865,20 @@ struct hnae3_handle { #define hnae3_get_bit(origin, shift) \ hnae3_get_field(origin, 0x1 << (shift), shift) =20 +#define HNAE3_FORMAT_MAC_ADDR_LEN 18 +#define HNAE3_FORMAT_MAC_ADDR_OFFSET_0 0 +#define HNAE3_FORMAT_MAC_ADDR_OFFSET_4 4 +#define HNAE3_FORMAT_MAC_ADDR_OFFSET_5 5 + +static inline void hnae3_format_mac_addr(char *format_mac_addr, + const u8 *mac_addr) +{ + snprintf(format_mac_addr, HNAE3_FORMAT_MAC_ADDR_LEN, "%02x:**:**:**:%02x:= %02x", + mac_addr[HNAE3_FORMAT_MAC_ADDR_OFFSET_0], + mac_addr[HNAE3_FORMAT_MAC_ADDR_OFFSET_4], + mac_addr[HNAE3_FORMAT_MAC_ADDR_OFFSET_5]); +} + int hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev); void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev); =20 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/n= et/ethernet/hisilicon/hns3/hns3_debugfs.c index c381f8af67f0..1b155d745218 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c @@ -1227,7 +1227,7 @@ static ssize_t hns3_dbg_read(struct file *filp, char = __user *buffer, return ret; =20 mutex_lock(&handle->dbgfs_lock); - save_buf =3D &hns3_dbg_cmd[index].buf; + save_buf =3D &handle->dbgfs_buf[index]; =20 if (!test_bit(HNS3_NIC_STATE_INITED, &priv->state) || test_bit(HNS3_NIC_STATE_RESETTING, &priv->state)) { @@ -1332,6 +1332,13 @@ int hns3_dbg_init(struct hnae3_handle *handle) int ret; u32 i; =20 + handle->dbgfs_buf =3D devm_kcalloc(&handle->pdev->dev, + ARRAY_SIZE(hns3_dbg_cmd), + sizeof(*handle->dbgfs_buf), + GFP_KERNEL); + if (!handle->dbgfs_buf) + return -ENOMEM; + hns3_dbg_dentry[HNS3_DBG_DENTRY_COMMON].dentry =3D debugfs_create_dir(name, hns3_dbgfs_root); handle->hnae3_dbgfs =3D hns3_dbg_dentry[HNS3_DBG_DENTRY_COMMON].dentry; @@ -1380,9 +1387,9 @@ void hns3_dbg_uninit(struct hnae3_handle *handle) u32 i; =20 for (i =3D 0; i < ARRAY_SIZE(hns3_dbg_cmd); i++) - if (hns3_dbg_cmd[i].buf) { - kvfree(hns3_dbg_cmd[i].buf); - hns3_dbg_cmd[i].buf =3D NULL; + if (handle->dbgfs_buf[i]) { + kvfree(handle->dbgfs_buf[i]); + handle->dbgfs_buf[i] =3D NULL; } =20 mutex_destroy(&handle->dbgfs_lock); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h b/drivers/n= et/ethernet/hisilicon/hns3/hns3_debugfs.h index bd8801065e02..814f7491ca08 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h @@ -47,7 +47,6 @@ struct hns3_dbg_cmd_info { enum hnae3_dbg_cmd cmd; enum hns3_dbg_dentry_type dentry; u32 buf_len; - char *buf; int (*init)(struct hnae3_handle *handle, unsigned int cmd); }; =20 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/= ethernet/hisilicon/hns3/hns3_enet.c index 9ccebbaa0d69..ef75223b0b55 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2255,6 +2255,8 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, st= ruct net_device *netdev) =20 static int hns3_nic_net_set_mac_address(struct net_device *netdev, void *p) { + char format_mac_addr_perm[HNAE3_FORMAT_MAC_ADDR_LEN]; + char format_mac_addr_sa[HNAE3_FORMAT_MAC_ADDR_LEN]; struct hnae3_handle *h =3D hns3_get_handle(netdev); struct sockaddr *mac_addr =3D p; int ret; @@ -2263,8 +2265,9 @@ static int hns3_nic_net_set_mac_address(struct net_de= vice *netdev, void *p) return -EADDRNOTAVAIL; =20 if (ether_addr_equal(netdev->dev_addr, mac_addr->sa_data)) { - netdev_info(netdev, "already using mac address %pM\n", - mac_addr->sa_data); + hnae3_format_mac_addr(format_mac_addr_sa, mac_addr->sa_data); + netdev_info(netdev, "already using mac address %s\n", + format_mac_addr_sa); return 0; } =20 @@ -2273,8 +2276,10 @@ static int hns3_nic_net_set_mac_address(struct net_d= evice *netdev, void *p) */ if (!hns3_is_phys_func(h->pdev) && !is_zero_ether_addr(netdev->perm_addr)) { - netdev_err(netdev, "has permanent MAC %pM, user MAC %pM not allow\n", - netdev->perm_addr, mac_addr->sa_data); + hnae3_format_mac_addr(format_mac_addr_perm, netdev->perm_addr); + hnae3_format_mac_addr(format_mac_addr_sa, mac_addr->sa_data); + netdev_err(netdev, "has permanent MAC %s, user MAC %s not allow\n", + format_mac_addr_perm, format_mac_addr_sa); return -EPERM; } =20 @@ -2836,14 +2841,16 @@ static int hns3_nic_set_vf_rate(struct net_device *= ndev, int vf, static int hns3_nic_set_vf_mac(struct net_device *netdev, int vf_id, u8 *m= ac) { struct hnae3_handle *h =3D hns3_get_handle(netdev); + char format_mac_addr[HNAE3_FORMAT_MAC_ADDR_LEN]; =20 if (!h->ae_algo->ops->set_vf_mac) return -EOPNOTSUPP; =20 if (is_multicast_ether_addr(mac)) { + hnae3_format_mac_addr(format_mac_addr, mac); netdev_err(netdev, - "Invalid MAC:%pM specified. Could not set MAC\n", - mac); + "Invalid MAC:%s specified. Could not set MAC\n", + format_mac_addr); return -EINVAL; } =20 @@ -2947,6 +2954,21 @@ static int hns3_probe(struct pci_dev *pdev, const st= ruct pci_device_id *ent) return ret; } =20 +/** + * hns3_clean_vf_config + * @pdev: pointer to a pci_dev structure + * @num_vfs: number of VFs allocated + * + * Clean residual vf config after disable sriov + **/ +static void hns3_clean_vf_config(struct pci_dev *pdev, int num_vfs) +{ + struct hnae3_ae_dev *ae_dev =3D pci_get_drvdata(pdev); + + if (ae_dev->ops->clean_vf_config) + ae_dev->ops->clean_vf_config(ae_dev, num_vfs); +} + /* hns3_remove - Device removal routine * @pdev: PCI device information struct */ @@ -2985,7 +3007,10 @@ static int hns3_pci_sriov_configure(struct pci_dev *= pdev, int num_vfs) else return num_vfs; } else if (!pci_vfs_assigned(pdev)) { + int num_vfs_pre =3D pci_num_vf(pdev); + pci_disable_sriov(pdev); + hns3_clean_vf_config(pdev, num_vfs_pre); } else { dev_warn(&pdev->dev, "Unable to free VFs because some are assigned to VMs.\n"); @@ -4934,6 +4959,7 @@ static void hns3_uninit_all_ring(struct hns3_nic_priv= *priv) static int hns3_init_mac_addr(struct net_device *netdev) { struct hns3_nic_priv *priv =3D netdev_priv(netdev); + char format_mac_addr[HNAE3_FORMAT_MAC_ADDR_LEN]; struct hnae3_handle *h =3D priv->ae_handle; u8 mac_addr_temp[ETH_ALEN]; int ret =3D 0; @@ -4944,8 +4970,9 @@ static int hns3_init_mac_addr(struct net_device *netd= ev) /* Check if the MAC address is valid, if not get a random one */ if (!is_valid_ether_addr(mac_addr_temp)) { eth_hw_addr_random(netdev); - dev_warn(priv->dev, "using random MAC address %pM\n", - netdev->dev_addr); + hnae3_format_mac_addr(format_mac_addr, netdev->dev_addr); + dev_warn(priv->dev, "using random MAC address %s\n", + format_mac_addr); } else if (!ether_addr_equal(netdev->dev_addr, mac_addr_temp)) { eth_hw_addr_set(netdev, mac_addr_temp); ether_addr_copy(netdev->perm_addr, mac_addr_temp); @@ -4997,8 +5024,10 @@ static void hns3_client_stop(struct hnae3_handle *ha= ndle) static void hns3_info_show(struct hns3_nic_priv *priv) { struct hnae3_knic_private_info *kinfo =3D &priv->ae_handle->kinfo; + char format_mac_addr[HNAE3_FORMAT_MAC_ADDR_LEN]; =20 - dev_info(priv->dev, "MAC address: %pM\n", priv->netdev->dev_addr); + hnae3_format_mac_addr(format_mac_addr, priv->netdev->dev_addr); + dev_info(priv->dev, "MAC address: %s\n", format_mac_addr); dev_info(priv->dev, "Task queue pairs numbers: %u\n", kinfo->num_tqps); dev_info(priv->dev, "RSS size: %u\n", kinfo->rss_size); dev_info(priv->dev, "Allocated RSS size: %u\n", kinfo->req_rss_size); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/driv= ers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index c2a58101144e..4ad08849e41a 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -1956,6 +1956,7 @@ static int hclge_alloc_vport(struct hclge_dev *hdev) vport->vf_info.link_state =3D IFLA_VF_LINK_STATE_AUTO; vport->mps =3D HCLGE_MAC_DEFAULT_FRAME; vport->port_base_vlan_cfg.state =3D HNAE3_PORT_BASE_VLAN_DISABLE; + vport->port_base_vlan_cfg.tbl_sta =3D true; vport->rxvlan_cfg.rx_vlan_offload_en =3D true; vport->req_vlan_fltr_en =3D true; INIT_LIST_HEAD(&vport->vlan_list); @@ -8743,6 +8744,7 @@ int hclge_update_mac_list(struct hclge_vport *vport, enum HCLGE_MAC_ADDR_TYPE mac_type, const unsigned char *addr) { + char format_mac_addr[HNAE3_FORMAT_MAC_ADDR_LEN]; struct hclge_dev *hdev =3D vport->back; struct hclge_mac_node *mac_node; struct list_head *list; @@ -8767,9 +8769,10 @@ int hclge_update_mac_list(struct hclge_vport *vport, /* if this address is never added, unnecessary to delete */ if (state =3D=3D HCLGE_MAC_TO_DEL) { spin_unlock_bh(&vport->mac_list_lock); + hnae3_format_mac_addr(format_mac_addr, addr); dev_err(&hdev->pdev->dev, - "failed to delete address %pM from mac list\n", - addr); + "failed to delete address %s from mac list\n", + format_mac_addr); return -ENOENT; } =20 @@ -8802,6 +8805,7 @@ static int hclge_add_uc_addr(struct hnae3_handle *han= dle, int hclge_add_uc_addr_common(struct hclge_vport *vport, const unsigned char *addr) { + char format_mac_addr[HNAE3_FORMAT_MAC_ADDR_LEN]; struct hclge_dev *hdev =3D vport->back; struct hclge_mac_vlan_tbl_entry_cmd req; struct hclge_desc desc; @@ -8812,9 +8816,10 @@ int hclge_add_uc_addr_common(struct hclge_vport *vpo= rt, if (is_zero_ether_addr(addr) || is_broadcast_ether_addr(addr) || is_multicast_ether_addr(addr)) { + hnae3_format_mac_addr(format_mac_addr, addr); dev_err(&hdev->pdev->dev, - "Set_uc mac err! invalid mac:%pM. is_zero:%d,is_br=3D%d,is_mul=3D%d\n", - addr, is_zero_ether_addr(addr), + "Set_uc mac err! invalid mac:%s. is_zero:%d,is_br=3D%d,is_mul=3D%d\n", + format_mac_addr, is_zero_ether_addr(addr), is_broadcast_ether_addr(addr), is_multicast_ether_addr(addr)); return -EINVAL; @@ -8871,6 +8876,7 @@ static int hclge_rm_uc_addr(struct hnae3_handle *hand= le, int hclge_rm_uc_addr_common(struct hclge_vport *vport, const unsigned char *addr) { + char format_mac_addr[HNAE3_FORMAT_MAC_ADDR_LEN]; struct hclge_dev *hdev =3D vport->back; struct hclge_mac_vlan_tbl_entry_cmd req; int ret; @@ -8879,8 +8885,9 @@ int hclge_rm_uc_addr_common(struct hclge_vport *vport, if (is_zero_ether_addr(addr) || is_broadcast_ether_addr(addr) || is_multicast_ether_addr(addr)) { - dev_dbg(&hdev->pdev->dev, "Remove mac err! invalid mac:%pM.\n", - addr); + hnae3_format_mac_addr(format_mac_addr, addr); + dev_dbg(&hdev->pdev->dev, "Remove mac err! invalid mac:%s.\n", + format_mac_addr); return -EINVAL; } =20 @@ -8888,12 +8895,11 @@ int hclge_rm_uc_addr_common(struct hclge_vport *vpo= rt, hnae3_set_bit(req.entry_type, HCLGE_MAC_VLAN_BIT0_EN_B, 0); hclge_prepare_mac_addr(&req, addr, false); ret =3D hclge_remove_mac_vlan_tbl(vport, &req); - if (!ret) { + if (!ret || ret =3D=3D -ENOENT) { mutex_lock(&hdev->vport_lock); hclge_update_umv_space(vport, true); mutex_unlock(&hdev->vport_lock); - } else if (ret =3D=3D -ENOENT) { - ret =3D 0; + return 0; } =20 return ret; @@ -8911,6 +8917,7 @@ static int hclge_add_mc_addr(struct hnae3_handle *han= dle, int hclge_add_mc_addr_common(struct hclge_vport *vport, const unsigned char *addr) { + char format_mac_addr[HNAE3_FORMAT_MAC_ADDR_LEN]; struct hclge_dev *hdev =3D vport->back; struct hclge_mac_vlan_tbl_entry_cmd req; struct hclge_desc desc[3]; @@ -8919,9 +8926,10 @@ int hclge_add_mc_addr_common(struct hclge_vport *vpo= rt, =20 /* mac addr check */ if (!is_multicast_ether_addr(addr)) { + hnae3_format_mac_addr(format_mac_addr, addr); dev_err(&hdev->pdev->dev, - "Add mc mac err! invalid mac:%pM.\n", - addr); + "Add mc mac err! invalid mac:%s.\n", + format_mac_addr); return -EINVAL; } memset(&req, 0, sizeof(req)); @@ -8973,6 +8981,7 @@ static int hclge_rm_mc_addr(struct hnae3_handle *hand= le, int hclge_rm_mc_addr_common(struct hclge_vport *vport, const unsigned char *addr) { + char format_mac_addr[HNAE3_FORMAT_MAC_ADDR_LEN]; struct hclge_dev *hdev =3D vport->back; struct hclge_mac_vlan_tbl_entry_cmd req; enum hclge_cmd_status status; @@ -8980,9 +8989,10 @@ int hclge_rm_mc_addr_common(struct hclge_vport *vpor= t, =20 /* mac addr check */ if (!is_multicast_ether_addr(addr)) { + hnae3_format_mac_addr(format_mac_addr, addr); dev_dbg(&hdev->pdev->dev, - "Remove mc mac err! invalid mac:%pM.\n", - addr); + "Remove mc mac err! invalid mac:%s.\n", + format_mac_addr); return -EINVAL; } =20 @@ -9422,30 +9432,37 @@ static int hclge_set_vf_mac(struct hnae3_handle *ha= ndle, int vf, u8 *mac_addr) { struct hclge_vport *vport =3D hclge_get_vport(handle); + char format_mac_addr[HNAE3_FORMAT_MAC_ADDR_LEN]; struct hclge_dev *hdev =3D vport->back; =20 vport =3D hclge_get_vf_vport(hdev, vf); if (!vport) return -EINVAL; =20 + hnae3_format_mac_addr(format_mac_addr, mac_addr); if (ether_addr_equal(mac_addr, vport->vf_info.mac)) { dev_info(&hdev->pdev->dev, - "Specified MAC(=3D%pM) is same as before, no change committed!\n", - mac_addr); + "Specified MAC(=3D%s) is same as before, no change committed!\n", + format_mac_addr); return 0; } =20 ether_addr_copy(vport->vf_info.mac, mac_addr); =20 + /* there is a timewindow for PF to know VF unalive, it may + * cause send mailbox fail, but it doesn't matter, VF will + * query it when reinit. + */ if (test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state)) { dev_info(&hdev->pdev->dev, - "MAC of VF %d has been set to %pM, and it will be reinitialized!\n", - vf, mac_addr); - return hclge_inform_reset_assert_to_vf(vport); + "MAC of VF %d has been set to %s, and it will be reinitialized!\n", + vf, format_mac_addr); + (void)hclge_inform_reset_assert_to_vf(vport); + return 0; } =20 - dev_info(&hdev->pdev->dev, "MAC of VF %d has been set to %pM\n", - vf, mac_addr); + dev_info(&hdev->pdev->dev, "MAC of VF %d has been set to %s\n", + vf, format_mac_addr); return 0; } =20 @@ -9549,6 +9566,7 @@ static int hclge_set_mac_addr(struct hnae3_handle *ha= ndle, const void *p, { const unsigned char *new_addr =3D (const unsigned char *)p; struct hclge_vport *vport =3D hclge_get_vport(handle); + char format_mac_addr[HNAE3_FORMAT_MAC_ADDR_LEN]; struct hclge_dev *hdev =3D vport->back; unsigned char *old_addr =3D NULL; int ret; @@ -9557,9 +9575,10 @@ static int hclge_set_mac_addr(struct hnae3_handle *h= andle, const void *p, if (is_zero_ether_addr(new_addr) || is_broadcast_ether_addr(new_addr) || is_multicast_ether_addr(new_addr)) { + hnae3_format_mac_addr(format_mac_addr, new_addr); dev_err(&hdev->pdev->dev, - "change uc mac err! invalid mac: %pM.\n", - new_addr); + "change uc mac err! invalid mac: %s.\n", + format_mac_addr); return -EINVAL; } =20 @@ -9577,9 +9596,10 @@ static int hclge_set_mac_addr(struct hnae3_handle *h= andle, const void *p, spin_lock_bh(&vport->mac_list_lock); ret =3D hclge_update_mac_node_for_dev_addr(vport, old_addr, new_addr); if (ret) { + hnae3_format_mac_addr(format_mac_addr, new_addr); dev_err(&hdev->pdev->dev, - "failed to change the mac addr:%pM, ret =3D %d\n", - new_addr, ret); + "failed to change the mac addr:%s, ret =3D %d\n", + format_mac_addr, ret); spin_unlock_bh(&vport->mac_list_lock); =20 if (!is_first) @@ -10237,19 +10257,28 @@ static void hclge_add_vport_vlan_table(struct hcl= ge_vport *vport, u16 vlan_id, bool writen_to_tbl) { struct hclge_vport_vlan_cfg *vlan, *tmp; + struct hclge_dev *hdev =3D vport->back; =20 - list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) - if (vlan->vlan_id =3D=3D vlan_id) + mutex_lock(&hdev->vport_lock); + + list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) { + if (vlan->vlan_id =3D=3D vlan_id) { + mutex_unlock(&hdev->vport_lock); return; + } + } =20 vlan =3D kzalloc(sizeof(*vlan), GFP_KERNEL); - if (!vlan) + if (!vlan) { + mutex_unlock(&hdev->vport_lock); return; + } =20 vlan->hd_tbl_status =3D writen_to_tbl; vlan->vlan_id =3D vlan_id; =20 list_add_tail(&vlan->node, &vport->vlan_list); + mutex_unlock(&hdev->vport_lock); } =20 static int hclge_add_vport_all_vlan_table(struct hclge_vport *vport) @@ -10258,6 +10287,8 @@ static int hclge_add_vport_all_vlan_table(struct hc= lge_vport *vport) struct hclge_dev *hdev =3D vport->back; int ret; =20 + mutex_lock(&hdev->vport_lock); + list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) { if (!vlan->hd_tbl_status) { ret =3D hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q), @@ -10267,12 +10298,16 @@ static int hclge_add_vport_all_vlan_table(struct = hclge_vport *vport) dev_err(&hdev->pdev->dev, "restore vport vlan list failed, ret=3D%d\n", ret); + + mutex_unlock(&hdev->vport_lock); return ret; } } vlan->hd_tbl_status =3D true; } =20 + mutex_unlock(&hdev->vport_lock); + return 0; } =20 @@ -10282,6 +10317,8 @@ static void hclge_rm_vport_vlan_table(struct hclge_= vport *vport, u16 vlan_id, struct hclge_vport_vlan_cfg *vlan, *tmp; struct hclge_dev *hdev =3D vport->back; =20 + mutex_lock(&hdev->vport_lock); + list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) { if (vlan->vlan_id =3D=3D vlan_id) { if (is_write_tbl && vlan->hd_tbl_status) @@ -10296,6 +10333,8 @@ static void hclge_rm_vport_vlan_table(struct hclge_= vport *vport, u16 vlan_id, break; } } + + mutex_unlock(&hdev->vport_lock); } =20 void hclge_rm_vport_all_vlan_table(struct hclge_vport *vport, bool is_del_= list) @@ -10303,6 +10342,8 @@ void hclge_rm_vport_all_vlan_table(struct hclge_vpo= rt *vport, bool is_del_list) struct hclge_vport_vlan_cfg *vlan, *tmp; struct hclge_dev *hdev =3D vport->back; =20 + mutex_lock(&hdev->vport_lock); + list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) { if (vlan->hd_tbl_status) hclge_set_vlan_filter_hw(hdev, @@ -10318,6 +10359,7 @@ void hclge_rm_vport_all_vlan_table(struct hclge_vpo= rt *vport, bool is_del_list) } } clear_bit(vport->vport_id, hdev->vf_vlan_full); + mutex_unlock(&hdev->vport_lock); } =20 void hclge_uninit_vport_vlan_table(struct hclge_dev *hdev) @@ -10326,6 +10368,8 @@ void hclge_uninit_vport_vlan_table(struct hclge_dev= *hdev) struct hclge_vport *vport; int i; =20 + mutex_lock(&hdev->vport_lock); + for (i =3D 0; i < hdev->num_alloc_vport; i++) { vport =3D &hdev->vport[i]; list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) { @@ -10333,37 +10377,61 @@ void hclge_uninit_vport_vlan_table(struct hclge_d= ev *hdev) kfree(vlan); } } + + mutex_unlock(&hdev->vport_lock); } =20 -void hclge_restore_vport_vlan_table(struct hclge_vport *vport) +void hclge_restore_vport_port_base_vlan_config(struct hclge_dev *hdev) { - struct hclge_vport_vlan_cfg *vlan, *tmp; - struct hclge_dev *hdev =3D vport->back; + struct hclge_vlan_info *vlan_info; + struct hclge_vport *vport; u16 vlan_proto; u16 vlan_id; u16 state; + int vf_id; int ret; =20 - vlan_proto =3D vport->port_base_vlan_cfg.vlan_info.vlan_proto; - vlan_id =3D vport->port_base_vlan_cfg.vlan_info.vlan_tag; - state =3D vport->port_base_vlan_cfg.state; + /* PF should restore all vfs port base vlan */ + for (vf_id =3D 0; vf_id < hdev->num_alloc_vfs; vf_id++) { + vport =3D &hdev->vport[vf_id + HCLGE_VF_VPORT_START_NUM]; + vlan_info =3D vport->port_base_vlan_cfg.tbl_sta ? + &vport->port_base_vlan_cfg.vlan_info : + &vport->port_base_vlan_cfg.old_vlan_info; =20 - if (state !=3D HNAE3_PORT_BASE_VLAN_DISABLE) { - clear_bit(vport->vport_id, hdev->vlan_table[vlan_id]); - hclge_set_vlan_filter_hw(hdev, htons(vlan_proto), - vport->vport_id, vlan_id, - false); - return; + vlan_id =3D vlan_info->vlan_tag; + vlan_proto =3D vlan_info->vlan_proto; + state =3D vport->port_base_vlan_cfg.state; + + if (state !=3D HNAE3_PORT_BASE_VLAN_DISABLE) { + clear_bit(vport->vport_id, hdev->vlan_table[vlan_id]); + ret =3D hclge_set_vlan_filter_hw(hdev, htons(vlan_proto), + vport->vport_id, + vlan_id, false); + vport->port_base_vlan_cfg.tbl_sta =3D ret =3D=3D 0; + } } +} =20 - list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) { - ret =3D hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q), - vport->vport_id, - vlan->vlan_id, false); - if (ret) - break; - vlan->hd_tbl_status =3D true; +void hclge_restore_vport_vlan_table(struct hclge_vport *vport) +{ + struct hclge_vport_vlan_cfg *vlan, *tmp; + struct hclge_dev *hdev =3D vport->back; + int ret; + + mutex_lock(&hdev->vport_lock); + + if (vport->port_base_vlan_cfg.state =3D=3D HNAE3_PORT_BASE_VLAN_DISABLE) { + list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) { + ret =3D hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q), + vport->vport_id, + vlan->vlan_id, false); + if (ret) + break; + vlan->hd_tbl_status =3D true; + } } + + mutex_unlock(&hdev->vport_lock); } =20 /* For global reset and imp reset, hardware will clear the mac table, @@ -10403,6 +10471,7 @@ static void hclge_restore_hw_table(struct hclge_dev= *hdev) struct hnae3_handle *handle =3D &vport->nic; =20 hclge_restore_mac_table_common(vport); + hclge_restore_vport_port_base_vlan_config(hdev); hclge_restore_vport_vlan_table(vport); set_bit(HCLGE_STATE_FD_USER_DEF_CHANGED, &hdev->state); hclge_restore_fd_entries(handle); @@ -10459,6 +10528,8 @@ static int hclge_update_vlan_filter_entries(struct = hclge_vport *vport, false); } =20 + vport->port_base_vlan_cfg.tbl_sta =3D false; + /* force add VLAN 0 */ ret =3D hclge_set_vf_vlan_common(hdev, vport->vport_id, false, 0); if (ret) @@ -10545,7 +10616,9 @@ int hclge_update_port_base_vlan_cfg(struct hclge_vp= ort *vport, u16 state, else nic->port_base_vlan_state =3D HNAE3_PORT_BASE_VLAN_ENABLE; =20 + vport->port_base_vlan_cfg.old_vlan_info =3D *old_vlan_info; vport->port_base_vlan_cfg.vlan_info =3D *vlan_info; + vport->port_base_vlan_cfg.tbl_sta =3D true; hclge_set_vport_vlan_fltr_change(vport); =20 return 0; @@ -10613,14 +10686,17 @@ static int hclge_set_vf_vlan_filter(struct hnae3_= handle *handle, int vfid, return ret; } =20 - /* for DEVICE_VERSION_V3, vf doesn't need to know about the port based + /* there is a timewindow for PF to know VF unalive, it may + * cause send mailbox fail, but it doesn't matter, VF will + * query it when reinit. + * for DEVICE_VERSION_V3, vf doesn't need to know about the port based * VLAN state. */ if (ae_dev->dev_version < HNAE3_DEVICE_VERSION_V3 && test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state)) - hclge_push_vf_port_base_vlan_info(&hdev->vport[0], - vport->vport_id, state, - &vlan_info); + (void)hclge_push_vf_port_base_vlan_info(&hdev->vport[0], + vport->vport_id, + state, &vlan_info); =20 return 0; } @@ -10678,11 +10754,11 @@ int hclge_set_vlan_filter(struct hnae3_handle *ha= ndle, __be16 proto, } =20 if (!ret) { - if (is_kill) - hclge_rm_vport_vlan_table(vport, vlan_id, false); - else + if (!is_kill) hclge_add_vport_vlan_table(vport, vlan_id, writen_to_tbl); + else if (is_kill && vlan_id !=3D 0) + hclge_rm_vport_vlan_table(vport, vlan_id, false); } else if (is_kill) { /* when remove hw vlan filter failed, record the vlan id, * and try to remove it from hw later, to be consistence @@ -12256,8 +12332,8 @@ static void hclge_uninit_ae_dev(struct hnae3_ae_dev= *ae_dev) hclge_misc_irq_uninit(hdev); hclge_devlink_uninit(hdev); hclge_pci_uninit(hdev); - mutex_destroy(&hdev->vport_lock); hclge_uninit_vport_vlan_table(hdev); + mutex_destroy(&hdev->vport_lock); ae_dev->priv =3D NULL; } =20 @@ -13070,6 +13146,55 @@ static int hclge_get_link_diagnosis_info(struct hn= ae3_handle *handle, return 0; } =20 +/* After disable sriov, VF still has some config and info need clean, + * which configed by PF. + */ +static void hclge_clear_vport_vf_info(struct hclge_vport *vport, int vfid) +{ + struct hclge_dev *hdev =3D vport->back; + struct hclge_vlan_info vlan_info; + int ret; + + /* after disable sriov, clean VF rate configured by PF */ + ret =3D hclge_tm_qs_shaper_cfg(vport, 0); + if (ret) + dev_err(&hdev->pdev->dev, + "failed to clean vf%d rate config, ret =3D %d\n", + vfid, ret); + + vlan_info.vlan_tag =3D 0; + vlan_info.qos =3D 0; + vlan_info.vlan_proto =3D ETH_P_8021Q; + ret =3D hclge_update_port_base_vlan_cfg(vport, + HNAE3_PORT_BASE_VLAN_DISABLE, + &vlan_info); + if (ret) + dev_err(&hdev->pdev->dev, + "failed to clean vf%d port base vlan, ret =3D %d\n", + vfid, ret); + + ret =3D hclge_set_vf_spoofchk_hw(hdev, vport->vport_id, false); + if (ret) + dev_err(&hdev->pdev->dev, + "failed to clean vf%d spoof config, ret =3D %d\n", + vfid, ret); + + memset(&vport->vf_info, 0, sizeof(vport->vf_info)); +} + +static void hclge_clean_vport_config(struct hnae3_ae_dev *ae_dev, int num_= vfs) +{ + struct hclge_dev *hdev =3D ae_dev->priv; + struct hclge_vport *vport; + int i; + + for (i =3D 0; i < num_vfs; i++) { + vport =3D &hdev->vport[i + HCLGE_VF_VPORT_START_NUM]; + + hclge_clear_vport_vf_info(vport, i); + } +} + static const struct hnae3_ae_ops hclge_ops =3D { .init_ae_dev =3D hclge_init_ae_dev, .uninit_ae_dev =3D hclge_uninit_ae_dev, @@ -13171,6 +13296,7 @@ static const struct hnae3_ae_ops hclge_ops =3D { .get_rx_hwts =3D hclge_ptp_get_rx_hwts, .get_ts_info =3D hclge_ptp_get_ts_info, .get_link_diagnosis_info =3D hclge_get_link_diagnosis_info, + .clean_vf_config =3D hclge_clean_vport_config, }; =20 static struct hnae3_ae_algo ae_algo =3D { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/driv= ers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index ebba603483a0..c841cce2d025 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -1030,7 +1030,9 @@ struct hclge_vlan_info { =20 struct hclge_port_base_vlan_config { u16 state; + bool tbl_sta; struct hclge_vlan_info vlan_info; + struct hclge_vlan_info old_vlan_info; }; =20 struct hclge_vf_info { @@ -1085,6 +1087,7 @@ struct hclge_vport { spinlock_t mac_list_lock; /* protect mac address need to add/detele */ struct list_head uc_mac_list; /* Store VF unicast table */ struct list_head mc_mac_list; /* Store VF multicast table */ + struct list_head vlan_list; /* Store VF vlan table */ }; =20 @@ -1154,6 +1157,7 @@ void hclge_rm_vport_all_mac_table(struct hclge_vport = *vport, bool is_del_list, void hclge_rm_vport_all_vlan_table(struct hclge_vport *vport, bool is_del_= list); void hclge_uninit_vport_vlan_table(struct hclge_dev *hdev); void hclge_restore_mac_table_common(struct hclge_vport *vport); +void hclge_restore_vport_port_base_vlan_config(struct hclge_dev *hdev); void hclge_restore_vport_vlan_table(struct hclge_vport *vport); int hclge_update_port_base_vlan_cfg(struct hclge_vport *vport, u16 state, struct hclge_vlan_info *vlan_info); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/dr= ivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 70491e07b0ff..7e30bad08356 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1514,15 +1514,18 @@ static void hclgevf_config_mac_list(struct hclgevf_= dev *hdev, struct list_head *list, enum HCLGEVF_MAC_ADDR_TYPE mac_type) { + char format_mac_addr[HNAE3_FORMAT_MAC_ADDR_LEN]; struct hclgevf_mac_addr_node *mac_node, *tmp; int ret; =20 list_for_each_entry_safe(mac_node, tmp, list, node) { ret =3D hclgevf_add_del_mac_addr(hdev, mac_node, mac_type); if (ret) { + hnae3_format_mac_addr(format_mac_addr, + mac_node->mac_addr); dev_err(&hdev->pdev->dev, - "failed to configure mac %pM, state =3D %d, ret =3D %d\n", - mac_node->mac_addr, mac_node->state, ret); + "failed to configure mac %s, state =3D %d, ret =3D %d\n", + format_mac_addr, mac_node->state, ret); return; } if (mac_node->state =3D=3D HCLGEVF_MAC_TO_ADD) { @@ -3341,6 +3344,11 @@ static int hclgevf_reset_hdev(struct hclgevf_dev *hd= ev) return ret; } =20 + /* get current port based vlan state from PF */ + ret =3D hclgevf_get_port_base_vlan_filter_state(hdev); + if (ret) + return ret; + set_bit(HCLGEVF_STATE_PROMISC_CHANGED, &hdev->state); =20 hclgevf_init_rxd_adv_layout(hdev); diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/= ibmvnic.c index a8b65c072f64..82f47bf4d67c 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1429,6 +1429,15 @@ static int __ibmvnic_open(struct net_device *netdev) return rc; } =20 + adapter->tx_queues_active =3D true; + + /* Since queues were stopped until now, there shouldn't be any + * one in ibmvnic_complete_tx() or ibmvnic_xmit() so maybe we + * don't need the synchronize_rcu()? Leaving it for consistency + * with setting ->tx_queues_active =3D false. + */ + synchronize_rcu(); + netif_tx_start_all_queues(netdev); =20 if (prev_state =3D=3D VNIC_CLOSED) { @@ -1603,6 +1612,14 @@ static void ibmvnic_cleanup(struct net_device *netde= v) struct ibmvnic_adapter *adapter =3D netdev_priv(netdev); =20 /* ensure that transmissions are stopped if called by do_reset */ + + adapter->tx_queues_active =3D false; + + /* Ensure complete_tx() and ibmvnic_xmit() see ->tx_queues_active + * update so they don't restart a queue after we stop it below. + */ + synchronize_rcu(); + if (test_bit(0, &adapter->resetting)) netif_tx_disable(netdev); else @@ -1842,14 +1859,21 @@ static void ibmvnic_tx_scrq_clean_buffer(struct ibm= vnic_adapter *adapter, tx_buff->skb =3D NULL; adapter->netdev->stats.tx_dropped++; } + ind_bufp->index =3D 0; + if (atomic_sub_return(entries, &tx_scrq->used) <=3D (adapter->req_tx_entries_per_subcrq / 2) && - __netif_subqueue_stopped(adapter->netdev, queue_num) && - !test_bit(0, &adapter->resetting)) { - netif_wake_subqueue(adapter->netdev, queue_num); - netdev_dbg(adapter->netdev, "Started queue %d\n", - queue_num); + __netif_subqueue_stopped(adapter->netdev, queue_num)) { + rcu_read_lock(); + + if (adapter->tx_queues_active) { + netif_wake_subqueue(adapter->netdev, queue_num); + netdev_dbg(adapter->netdev, "Started queue %d\n", + queue_num); + } + + rcu_read_unlock(); } } =20 @@ -1904,11 +1928,12 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb= , struct net_device *netdev) int index =3D 0; u8 proto =3D 0; =20 - tx_scrq =3D adapter->tx_scrq[queue_num]; - txq =3D netdev_get_tx_queue(netdev, queue_num); - ind_bufp =3D &tx_scrq->ind_buf; - - if (test_bit(0, &adapter->resetting)) { + /* If a reset is in progress, drop the packet since + * the scrqs may get torn down. Otherwise use the + * rcu to ensure reset waits for us to complete. + */ + rcu_read_lock(); + if (!adapter->tx_queues_active) { dev_kfree_skb_any(skb); =20 tx_send_failed++; @@ -1917,6 +1942,10 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb,= struct net_device *netdev) goto out; } =20 + tx_scrq =3D adapter->tx_scrq[queue_num]; + txq =3D netdev_get_tx_queue(netdev, queue_num); + ind_bufp =3D &tx_scrq->ind_buf; + if (ibmvnic_xmit_workarounds(skb, netdev)) { tx_dropped++; tx_send_failed++; @@ -1924,6 +1953,7 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, = struct net_device *netdev) ibmvnic_tx_scrq_flush(adapter, tx_scrq); goto out; } + if (skb_is_gso(skb)) tx_pool =3D &adapter->tso_pool[queue_num]; else @@ -2078,6 +2108,7 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, = struct net_device *netdev) netif_carrier_off(netdev); } out: + rcu_read_unlock(); netdev->stats.tx_dropped +=3D tx_dropped; netdev->stats.tx_bytes +=3D tx_bytes; netdev->stats.tx_packets +=3D tx_packets; @@ -3728,9 +3759,15 @@ static int ibmvnic_complete_tx(struct ibmvnic_adapte= r *adapter, (adapter->req_tx_entries_per_subcrq / 2) && __netif_subqueue_stopped(adapter->netdev, scrq->pool_index)) { - netif_wake_subqueue(adapter->netdev, scrq->pool_index); - netdev_dbg(adapter->netdev, "Started queue %d\n", - scrq->pool_index); + rcu_read_lock(); + if (adapter->tx_queues_active) { + netif_wake_subqueue(adapter->netdev, + scrq->pool_index); + netdev_dbg(adapter->netdev, + "Started queue %d\n", + scrq->pool_index); + } + rcu_read_unlock(); } } =20 diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/= ibmvnic.h index 549a9b7b1a70..1b2bdb85ad67 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -1009,11 +1009,14 @@ struct ibmvnic_adapter { struct work_struct ibmvnic_reset; struct delayed_work ibmvnic_delayed_reset; unsigned long resetting; - bool napi_enabled, from_passive_init; - bool login_pending; /* last device reset time */ unsigned long last_reset_time; =20 + bool napi_enabled; + bool from_passive_init; + bool login_pending; + /* protected by rcu */ + bool tx_queues_active; bool failover_pending; bool force_reset_recovery; =20 diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ether= net/intel/i40e/i40e_xsk.c index ea06e957393e..0e8cf275e084 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c @@ -218,7 +218,6 @@ bool i40e_alloc_rx_buffers_zc(struct i40e_ring *rx_ring= , u16 count) ntu +=3D nb_buffs; if (ntu =3D=3D rx_ring->count) { rx_desc =3D I40E_RX_DESC(rx_ring, 0); - xdp =3D i40e_rx_bi(rx_ring, 0); ntu =3D 0; } =20 @@ -241,21 +240,25 @@ bool i40e_alloc_rx_buffers_zc(struct i40e_ring *rx_ri= ng, u16 count) static struct sk_buff *i40e_construct_skb_zc(struct i40e_ring *rx_ring, struct xdp_buff *xdp) { + unsigned int totalsize =3D xdp->data_end - xdp->data_meta; unsigned int metasize =3D xdp->data - xdp->data_meta; - unsigned int datasize =3D xdp->data_end - xdp->data; struct sk_buff *skb; =20 + net_prefetch(xdp->data_meta); + /* allocate a skb to store the frags */ - skb =3D __napi_alloc_skb(&rx_ring->q_vector->napi, - xdp->data_end - xdp->data_hard_start, + skb =3D __napi_alloc_skb(&rx_ring->q_vector->napi, totalsize, GFP_ATOMIC | __GFP_NOWARN); if (unlikely(!skb)) goto out; =20 - skb_reserve(skb, xdp->data - xdp->data_hard_start); - memcpy(__skb_put(skb, datasize), xdp->data, datasize); - if (metasize) + memcpy(__skb_put(skb, totalsize), xdp->data_meta, + ALIGN(totalsize, sizeof(long))); + + if (metasize) { skb_metadata_set(skb, metasize); + __skb_pull(skb, metasize); + } =20 out: xsk_buff_free(xdp); @@ -324,11 +327,11 @@ static void i40e_handle_xdp_result_zc(struct i40e_rin= g *rx_ring, int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget) { unsigned int total_rx_bytes =3D 0, total_rx_packets =3D 0; - u16 cleaned_count =3D I40E_DESC_UNUSED(rx_ring); u16 next_to_clean =3D rx_ring->next_to_clean; u16 count_mask =3D rx_ring->count - 1; unsigned int xdp_res, xdp_xmit =3D 0; bool failure =3D false; + u16 cleaned_count; =20 while (likely(total_rx_packets < (unsigned int)budget)) { union i40e_rx_desc *rx_desc; diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/in= tel/ice/ice.h index 8093346f163b..a47471586047 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -290,6 +290,7 @@ enum ice_pf_state { ICE_LINK_DEFAULT_OVERRIDE_PENDING, ICE_PHY_INIT_COMPLETE, ICE_FD_VF_FLUSH_CTX, /* set at FD Rx IRQ or timeout */ + ICE_AUX_ERR_PENDING, ICE_STATE_NBITS /* must be last */ }; =20 @@ -557,6 +558,7 @@ struct ice_pf { wait_queue_head_t reset_wait_queue; =20 u32 hw_csum_rx_error; + u32 oicr_err_reg; u16 oicr_idx; /* Other interrupt cause MSIX vector index */ u16 num_avail_sw_msix; /* remaining MSIX SW vectors left unclaimed */ u16 max_pf_txqs; /* Total Tx queues PF wide */ @@ -707,7 +709,7 @@ static inline struct xsk_buff_pool *ice_tx_xsk_pool(str= uct ice_tx_ring *ring) struct ice_vsi *vsi =3D ring->vsi; u16 qid; =20 - qid =3D ring->q_index - vsi->num_xdp_txq; + qid =3D ring->q_index - vsi->alloc_txq; =20 if (!ice_is_xdp_ena_vsi(vsi) || !test_bit(qid, vsi->af_xdp_zc_qps)) return NULL; diff --git a/drivers/net/ethernet/intel/ice/ice_idc.c b/drivers/net/etherne= t/intel/ice/ice_idc.c index adcc9a251595..a2714988dd96 100644 --- a/drivers/net/ethernet/intel/ice/ice_idc.c +++ b/drivers/net/ethernet/intel/ice/ice_idc.c @@ -34,6 +34,9 @@ void ice_send_event_to_aux(struct ice_pf *pf, struct iidc= _event *event) { struct iidc_auxiliary_drv *iadrv; =20 + if (WARN_ON_ONCE(!in_task())) + return; + if (!pf->adev) return; =20 diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethern= et/intel/ice/ice_main.c index b449b3408a1c..523877c2f8b6 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -2237,6 +2237,19 @@ static void ice_service_task(struct work_struct *wor= k) return; } =20 + if (test_and_clear_bit(ICE_AUX_ERR_PENDING, pf->state)) { + struct iidc_event *event; + + event =3D kzalloc(sizeof(*event), GFP_KERNEL); + if (event) { + set_bit(IIDC_EVENT_CRIT_ERR, event->type); + /* report the entire OICR value to AUX driver */ + swap(event->reg, pf->oicr_err_reg); + ice_send_event_to_aux(pf, event); + kfree(event); + } + } + if (test_bit(ICE_FLAG_PLUG_AUX_DEV, pf->flags)) { /* Plug aux device per request */ ice_plug_aux_dev(pf); @@ -3023,17 +3036,9 @@ static irqreturn_t ice_misc_intr(int __always_unused= irq, void *data) =20 #define ICE_AUX_CRIT_ERR (PFINT_OICR_PE_CRITERR_M | PFINT_OICR_HMC_ERR_M |= PFINT_OICR_PE_PUSH_M) if (oicr & ICE_AUX_CRIT_ERR) { - struct iidc_event *event; - + pf->oicr_err_reg |=3D oicr; + set_bit(ICE_AUX_ERR_PENDING, pf->state); ena_mask &=3D ~ICE_AUX_CRIT_ERR; - event =3D kzalloc(sizeof(*event), GFP_ATOMIC); - if (event) { - set_bit(IIDC_EVENT_CRIT_ERR, event->type); - /* report the entire OICR value to AUX driver */ - event->reg =3D oicr; - ice_send_event_to_aux(pf, event); - kfree(event); - } } =20 /* Report any remaining unexpected interrupts */ diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/etherne= t/intel/ice/ice_xsk.c index c895351b25e0..ac97cf3c5804 100644 --- a/drivers/net/ethernet/intel/ice/ice_xsk.c +++ b/drivers/net/ethernet/intel/ice/ice_xsk.c @@ -428,20 +428,24 @@ static void ice_bump_ntc(struct ice_rx_ring *rx_ring) static struct sk_buff * ice_construct_skb_zc(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp) { - unsigned int datasize_hard =3D xdp->data_end - xdp->data_hard_start; + unsigned int totalsize =3D xdp->data_end - xdp->data_meta; unsigned int metasize =3D xdp->data - xdp->data_meta; - unsigned int datasize =3D xdp->data_end - xdp->data; struct sk_buff *skb; =20 - skb =3D __napi_alloc_skb(&rx_ring->q_vector->napi, datasize_hard, + net_prefetch(xdp->data_meta); + + skb =3D __napi_alloc_skb(&rx_ring->q_vector->napi, totalsize, GFP_ATOMIC | __GFP_NOWARN); if (unlikely(!skb)) return NULL; =20 - skb_reserve(skb, xdp->data - xdp->data_hard_start); - memcpy(__skb_put(skb, datasize), xdp->data, datasize); - if (metasize) + memcpy(__skb_put(skb, totalsize), xdp->data_meta, + ALIGN(totalsize, sizeof(long))); + + if (metasize) { skb_metadata_set(skb, metasize); + __skb_pull(skb, metasize); + } =20 xsk_buff_free(xdp); return skb; diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/eth= ernet/intel/igb/igb_ethtool.c index fb1029352c3e..3cbb5a89b336 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -961,10 +961,6 @@ static int igb_set_ringparam(struct net_device *netdev, memcpy(&temp_ring[i], adapter->rx_ring[i], sizeof(struct igb_ring)); =20 - /* Clear copied XDP RX-queue info */ - memset(&temp_ring[i].xdp_rxq, 0, - sizeof(temp_ring[i].xdp_rxq)); - temp_ring[i].count =3D new_rx_count; err =3D igb_setup_rx_resources(&temp_ring[i]); if (err) { diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethern= et/intel/igb/igb_main.c index 446894dde182..5034ebb57b65 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -4352,7 +4352,18 @@ int igb_setup_rx_resources(struct igb_ring *rx_ring) { struct igb_adapter *adapter =3D netdev_priv(rx_ring->netdev); struct device *dev =3D rx_ring->dev; - int size; + int size, res; + + /* XDP RX-queue info */ + if (xdp_rxq_info_is_reg(&rx_ring->xdp_rxq)) + xdp_rxq_info_unreg(&rx_ring->xdp_rxq); + res =3D xdp_rxq_info_reg(&rx_ring->xdp_rxq, rx_ring->netdev, + rx_ring->queue_index, 0); + if (res < 0) { + dev_err(dev, "Failed to register xdp_rxq index %u\n", + rx_ring->queue_index); + return res; + } =20 size =3D sizeof(struct igb_rx_buffer) * rx_ring->count; =20 @@ -4375,14 +4386,10 @@ int igb_setup_rx_resources(struct igb_ring *rx_ring) =20 rx_ring->xdp_prog =3D adapter->xdp_prog; =20 - /* XDP RX-queue info */ - if (xdp_rxq_info_reg(&rx_ring->xdp_rxq, rx_ring->netdev, - rx_ring->queue_index, 0) < 0) - goto err; - return 0; =20 err: + xdp_rxq_info_unreg(&rx_ring->xdp_rxq); vfree(rx_ring->rx_buffer_info); rx_ring->rx_buffer_info =3D NULL; dev_err(dev, "Unable to allocate memory for the Rx descriptor ring\n"); diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethern= et/intel/igc/igc_main.c index d83e665b3a4f..0000eae0d729 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -505,6 +505,9 @@ int igc_setup_rx_resources(struct igc_ring *rx_ring) u8 index =3D rx_ring->queue_index; int size, desc_len, res; =20 + /* XDP RX-queue info */ + if (xdp_rxq_info_is_reg(&rx_ring->xdp_rxq)) + xdp_rxq_info_unreg(&rx_ring->xdp_rxq); res =3D xdp_rxq_info_reg(&rx_ring->xdp_rxq, ndev, index, rx_ring->q_vector->napi.napi_id); if (res < 0) { @@ -2435,19 +2438,20 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_= vector, const int budget) static struct sk_buff *igc_construct_skb_zc(struct igc_ring *ring, struct xdp_buff *xdp) { + unsigned int totalsize =3D xdp->data_end - xdp->data_meta; unsigned int metasize =3D xdp->data - xdp->data_meta; - unsigned int datasize =3D xdp->data_end - xdp->data; - unsigned int totalsize =3D metasize + datasize; struct sk_buff *skb; =20 - skb =3D __napi_alloc_skb(&ring->q_vector->napi, - xdp->data_end - xdp->data_hard_start, + net_prefetch(xdp->data_meta); + + skb =3D __napi_alloc_skb(&ring->q_vector->napi, totalsize, GFP_ATOMIC | __GFP_NOWARN); if (unlikely(!skb)) return NULL; =20 - skb_reserve(skb, xdp->data_meta - xdp->data_hard_start); - memcpy(__skb_put(skb, totalsize), xdp->data_meta, totalsize); + memcpy(__skb_put(skb, totalsize), xdp->data_meta, + ALIGN(totalsize, sizeof(long))); + if (metasize) { skb_metadata_set(skb, metasize); __skb_pull(skb, metasize); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c b/drivers/net/eth= ernet/intel/ixgbe/ixgbe_xsk.c index 666ff2c07ab9..92a5080f8201 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c @@ -207,26 +207,28 @@ bool ixgbe_alloc_rx_buffers_zc(struct ixgbe_ring *rx_= ring, u16 count) } =20 static struct sk_buff *ixgbe_construct_skb_zc(struct ixgbe_ring *rx_ring, - struct ixgbe_rx_buffer *bi) + const struct xdp_buff *xdp) { - unsigned int metasize =3D bi->xdp->data - bi->xdp->data_meta; - unsigned int datasize =3D bi->xdp->data_end - bi->xdp->data; + unsigned int totalsize =3D xdp->data_end - xdp->data_meta; + unsigned int metasize =3D xdp->data - xdp->data_meta; struct sk_buff *skb; =20 + net_prefetch(xdp->data_meta); + /* allocate a skb to store the frags */ - skb =3D __napi_alloc_skb(&rx_ring->q_vector->napi, - bi->xdp->data_end - bi->xdp->data_hard_start, + skb =3D __napi_alloc_skb(&rx_ring->q_vector->napi, totalsize, GFP_ATOMIC | __GFP_NOWARN); if (unlikely(!skb)) return NULL; =20 - skb_reserve(skb, bi->xdp->data - bi->xdp->data_hard_start); - memcpy(__skb_put(skb, datasize), bi->xdp->data, datasize); - if (metasize) + memcpy(__skb_put(skb, totalsize), xdp->data_meta, + ALIGN(totalsize, sizeof(long))); + + if (metasize) { skb_metadata_set(skb, metasize); + __skb_pull(skb, metasize); + } =20 - xsk_buff_free(bi->xdp); - bi->xdp =3D NULL; return skb; } =20 @@ -317,12 +319,15 @@ int ixgbe_clean_rx_irq_zc(struct ixgbe_q_vector *q_ve= ctor, } =20 /* XDP_PASS path */ - skb =3D ixgbe_construct_skb_zc(rx_ring, bi); + skb =3D ixgbe_construct_skb_zc(rx_ring, bi->xdp); if (!skb) { rx_ring->rx_stats.alloc_rx_buff_failed++; break; } =20 + xsk_buff_free(bi->xdp); + bi->xdp =3D NULL; + cleaned_count++; ixgbe_inc_ntc(rx_ring); =20 diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/= net/ethernet/marvell/octeontx2/af/rvu_npc.c index 91f86d77cd41..3a31fb8cc155 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c @@ -605,7 +605,7 @@ void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 p= cifunc, struct npc_install_flow_req req =3D { 0 }; struct npc_install_flow_rsp rsp =3D { 0 }; struct npc_mcam *mcam =3D &rvu->hw->mcam; - struct nix_rx_action action; + struct nix_rx_action action =3D { 0 }; int blkaddr, index; =20 /* AF's and SDP VFs work in promiscuous mode */ @@ -626,7 +626,6 @@ void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 p= cifunc, *(u64 *)&action =3D npc_get_mcam_action(rvu, mcam, blkaddr, index); } else { - *(u64 *)&action =3D 0x00; action.op =3D NIX_RX_ACTIONOP_UCAST; action.pf_func =3D pcifunc; } @@ -657,7 +656,7 @@ void rvu_npc_install_promisc_entry(struct rvu *rvu, u16= pcifunc, struct npc_mcam *mcam =3D &rvu->hw->mcam; struct rvu_hwinfo *hw =3D rvu->hw; int blkaddr, ucast_idx, index; - struct nix_rx_action action; + struct nix_rx_action action =3D { 0 }; u64 relaxed_mask; =20 if (!hw->cap.nix_rx_multicast && is_cgx_vf(rvu, pcifunc)) @@ -685,14 +684,14 @@ void rvu_npc_install_promisc_entry(struct rvu *rvu, u= 16 pcifunc, blkaddr, ucast_idx); =20 if (action.op !=3D NIX_RX_ACTIONOP_RSS) { - *(u64 *)&action =3D 0x00; + *(u64 *)&action =3D 0; action.op =3D NIX_RX_ACTIONOP_UCAST; } =20 /* RX_ACTION set to MCAST for CGX PF's */ if (hw->cap.nix_rx_multicast && pfvf->use_mce_list && is_pf_cgxmapped(rvu, rvu_get_pf(pcifunc))) { - *(u64 *)&action =3D 0x00; + *(u64 *)&action =3D 0; action.op =3D NIX_RX_ACTIONOP_MCAST; pfvf =3D rvu_get_pfvf(rvu, pcifunc & ~RVU_PFVF_FUNC_MASK); action.index =3D pfvf->promisc_mce_idx; @@ -832,7 +831,7 @@ void rvu_npc_install_allmulti_entry(struct rvu *rvu, u1= 6 pcifunc, int nixlf, struct rvu_hwinfo *hw =3D rvu->hw; int blkaddr, ucast_idx, index; u8 mac_addr[ETH_ALEN] =3D { 0 }; - struct nix_rx_action action; + struct nix_rx_action action =3D { 0 }; struct rvu_pfvf *pfvf; u16 vf_func; =20 @@ -861,14 +860,14 @@ void rvu_npc_install_allmulti_entry(struct rvu *rvu, = u16 pcifunc, int nixlf, blkaddr, ucast_idx); =20 if (action.op !=3D NIX_RX_ACTIONOP_RSS) { - *(u64 *)&action =3D 0x00; + *(u64 *)&action =3D 0; action.op =3D NIX_RX_ACTIONOP_UCAST; action.pf_func =3D pcifunc; } =20 /* RX_ACTION set to MCAST for CGX PF's */ if (hw->cap.nix_rx_multicast && pfvf->use_mce_list) { - *(u64 *)&action =3D 0x00; + *(u64 *)&action =3D 0; action.op =3D NIX_RX_ACTIONOP_MCAST; action.index =3D pfvf->mcast_mce_idx; } diff --git a/drivers/net/ethernet/microchip/sparx5/Kconfig b/drivers/net/et= hernet/microchip/sparx5/Kconfig index 7bdbb2d09a14..cc5e48e1bb4c 100644 --- a/drivers/net/ethernet/microchip/sparx5/Kconfig +++ b/drivers/net/ethernet/microchip/sparx5/Kconfig @@ -4,6 +4,8 @@ config SPARX5_SWITCH depends on HAS_IOMEM depends on OF depends on ARCH_SPARX5 || COMPILE_TEST + depends on PTP_1588_CLOCK_OPTIONAL + depends on BRIDGE || BRIDGE=3Dn select PHYLINK select PHY_SPARX5_SERDES select RESET_CONTROLLER diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c b/drivers/= net/ethernet/microchip/sparx5/sparx5_fdma.c index 7436f62fa152..174ad95e746a 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c @@ -420,6 +420,8 @@ static int sparx5_fdma_tx_alloc(struct sparx5 *sparx5) db_hw->dataptr =3D phys; db_hw->status =3D 0; db =3D devm_kzalloc(sparx5->dev, sizeof(*db), GFP_KERNEL); + if (!db) + return -ENOMEM; db->cpu_addr =3D cpu_addr; list_add_tail(&db->list, &tx->db_list); } diff --git a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c b/drivers/= net/ethernet/pensando/ionic/ionic_bus_pci.c index 7e296fa71b36..40fa5bce2ac2 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c @@ -331,6 +331,9 @@ static int ionic_probe(struct pci_dev *pdev, const stru= ct pci_device_id *ent) goto err_out_deregister_lifs; } =20 + mod_timer(&ionic->watchdog_timer, + round_jiffies(jiffies + ionic->watchdog_period)); + return 0; =20 err_out_deregister_lifs: @@ -348,7 +351,6 @@ static int ionic_probe(struct pci_dev *pdev, const stru= ct pci_device_id *ent) err_out_reset: ionic_reset(ionic); err_out_teardown: - del_timer_sync(&ionic->watchdog_timer); pci_clear_master(pdev); /* Don't fail the probe for these errors, keep * the hw interface around for inspection diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/= ethernet/pensando/ionic/ionic_dev.c index d57e80d44c9d..2c7ce820a1fa 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c @@ -122,9 +122,6 @@ int ionic_dev_setup(struct ionic *ionic) idev->fw_generation =3D IONIC_FW_STS_F_GENERATION & ioread8(&idev->dev_info_regs->fw_status); =20 - mod_timer(&ionic->watchdog_timer, - round_jiffies(jiffies + ionic->watchdog_period)); - idev->db_pages =3D bar->vaddr; idev->phy_db_pages =3D bar->bus_addr; =20 @@ -132,6 +129,16 @@ int ionic_dev_setup(struct ionic *ionic) } =20 /* Devcmd Interface */ +bool ionic_is_fw_running(struct ionic_dev *idev) +{ + u8 fw_status =3D ioread8(&idev->dev_info_regs->fw_status); + + /* firmware is useful only if the running bit is set and + * fw_status !=3D 0xff (bad PCI read) + */ + return (fw_status !=3D 0xff) && (fw_status & IONIC_FW_STS_F_RUNNING); +} + int ionic_heartbeat_check(struct ionic *ionic) { struct ionic_dev *idev =3D &ionic->idev; @@ -155,13 +162,10 @@ int ionic_heartbeat_check(struct ionic *ionic) goto do_check_time; } =20 - /* firmware is useful only if the running bit is set and - * fw_status !=3D 0xff (bad PCI read) - * If fw_status is not ready don't bother with the generation. - */ fw_status =3D ioread8(&idev->dev_info_regs->fw_status); =20 - if (fw_status =3D=3D 0xff || !(fw_status & IONIC_FW_STS_F_RUNNING)) { + /* If fw_status is not ready don't bother with the generation */ + if (!ionic_is_fw_running(idev)) { fw_status_ready =3D false; } else { fw_generation =3D fw_status & IONIC_FW_STS_F_GENERATION; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/= ethernet/pensando/ionic/ionic_dev.h index e5acf3bd62b2..73b950ac1272 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -353,5 +353,6 @@ void ionic_q_rewind(struct ionic_queue *q, struct ionic= _desc_info *start); void ionic_q_service(struct ionic_queue *q, struct ionic_cq_info *cq_info, unsigned int stop_index); int ionic_heartbeat_check(struct ionic *ionic); +bool ionic_is_fw_running(struct ionic_dev *idev); =20 #endif /* _IONIC_DEV_H_ */ diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net= /ethernet/pensando/ionic/ionic_main.c index 875f4ec42efe..a0f9136b2d89 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_main.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c @@ -215,9 +215,13 @@ static void ionic_adminq_flush(struct ionic_lif *lif) void ionic_adminq_netdev_err_print(struct ionic_lif *lif, u8 opcode, u8 status, int err) { + const char *stat_str; + + stat_str =3D (err =3D=3D -ETIMEDOUT) ? "TIMEOUT" : + ionic_error_to_str(status); + netdev_err(lif->netdev, "%s (%d) failed: %s (%d)\n", - ionic_opcode_to_str(opcode), opcode, - ionic_error_to_str(status), err); + ionic_opcode_to_str(opcode), opcode, stat_str, err); } =20 static int ionic_adminq_check_err(struct ionic_lif *lif, @@ -318,6 +322,7 @@ int ionic_adminq_wait(struct ionic_lif *lif, struct ion= ic_admin_ctx *ctx, if (do_msg && !test_bit(IONIC_LIF_F_FW_RESET, lif->state)) netdev_err(netdev, "Posting of %s (%d) failed: %d\n", name, ctx->cmd.cmd.opcode, err); + ctx->comp.comp.status =3D IONIC_RC_ERROR; return err; } =20 @@ -336,6 +341,7 @@ int ionic_adminq_wait(struct ionic_lif *lif, struct ion= ic_admin_ctx *ctx, if (do_msg) netdev_err(netdev, "%s (%d) interrupted, FW in reset\n", name, ctx->cmd.cmd.opcode); + ctx->comp.comp.status =3D IONIC_RC_ERROR; return -ENXIO; } =20 @@ -370,10 +376,10 @@ int ionic_adminq_post_wait_nomsg(struct ionic_lif *li= f, struct ionic_admin_ctx * =20 static void ionic_dev_cmd_clean(struct ionic *ionic) { - union __iomem ionic_dev_cmd_regs *regs =3D ionic->idev.dev_cmd_regs; + struct ionic_dev *idev =3D &ionic->idev; =20 - iowrite32(0, ®s->doorbell); - memset_io(®s->cmd, 0, sizeof(regs->cmd)); + iowrite32(0, &idev->dev_cmd_regs->doorbell); + memset_io(&idev->dev_cmd_regs->cmd, 0, sizeof(idev->dev_cmd_regs->cmd)); } =20 int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds) @@ -540,6 +546,9 @@ int ionic_reset(struct ionic *ionic) struct ionic_dev *idev =3D &ionic->idev; int err; =20 + if (!ionic_is_fw_running(idev)) + return 0; + mutex_lock(&ionic->dev_cmd_lock); ionic_dev_cmd_reset(idev); err =3D ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); @@ -612,15 +621,17 @@ int ionic_port_init(struct ionic *ionic) int ionic_port_reset(struct ionic *ionic) { struct ionic_dev *idev =3D &ionic->idev; - int err; + int err =3D 0; =20 if (!idev->port_info) return 0; =20 - mutex_lock(&ionic->dev_cmd_lock); - ionic_dev_cmd_port_reset(idev); - err =3D ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); - mutex_unlock(&ionic->dev_cmd_lock); + if (ionic_is_fw_running(idev)) { + mutex_lock(&ionic->dev_cmd_lock); + ionic_dev_cmd_port_reset(idev); + err =3D ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); + mutex_unlock(&ionic->dev_cmd_lock); + } =20 dma_free_coherent(ionic->dev, idev->port_info_sz, idev->port_info, idev->port_info_pa); @@ -628,9 +639,6 @@ int ionic_port_reset(struct ionic *ionic) idev->port_info =3D NULL; idev->port_info_pa =3D 0; =20 - if (err) - dev_err(ionic->dev, "Failed to reset port\n"); - return err; } =20 diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethe= rnet/qlogic/qed/qed_sriov.c index 48cf4355bc47..0848b5529d48 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -2984,12 +2984,16 @@ static int qed_iov_pre_update_vport(struct qed_hwfn= *hwfn, u8 mask =3D QED_ACCEPT_UCAST_UNMATCHED | QED_ACCEPT_MCAST_UNMATCHED; struct qed_filter_accept_flags *flags =3D ¶ms->accept_flags; struct qed_public_vf_info *vf_info; + u16 tlv_mask; + + tlv_mask =3D BIT(QED_IOV_VP_UPDATE_ACCEPT_PARAM) | + BIT(QED_IOV_VP_UPDATE_ACCEPT_ANY_VLAN); =20 /* Untrusted VFs can't even be trusted to know that fact. * Simply indicate everything is configured fine, and trace * configuration 'behind their back'. */ - if (!(*tlvs & BIT(QED_IOV_VP_UPDATE_ACCEPT_PARAM))) + if (!(*tlvs & tlv_mask)) return 0; =20 vf_info =3D qed_iov_get_public_vf_info(hwfn, vfid, true); @@ -3006,6 +3010,13 @@ static int qed_iov_pre_update_vport(struct qed_hwfn = *hwfn, flags->tx_accept_filter &=3D ~mask; } =20 + if (params->update_accept_any_vlan_flg) { + vf_info->accept_any_vlan =3D params->accept_any_vlan; + + if (vf_info->forced_vlan && !vf_info->is_trusted_configured) + params->accept_any_vlan =3D false; + } + return 0; } =20 @@ -4719,6 +4730,7 @@ static int qed_get_vf_config(struct qed_dev *cdev, tx_rate =3D vf_info->tx_rate; ivi->max_tx_rate =3D tx_rate ? tx_rate : link.speed; ivi->min_tx_rate =3D qed_iov_get_vf_min_rate(hwfn, vf_id); + ivi->trusted =3D vf_info->is_trusted_request; =20 return 0; } @@ -5149,6 +5161,12 @@ static void qed_iov_handle_trust_change(struct qed_h= wfn *hwfn) =20 params.update_ctl_frame_check =3D 1; params.mac_chk_en =3D !vf_info->is_trusted_configured; + params.update_accept_any_vlan_flg =3D 0; + + if (vf_info->accept_any_vlan && vf_info->forced_vlan) { + params.update_accept_any_vlan_flg =3D 1; + params.accept_any_vlan =3D vf_info->accept_any_vlan; + } =20 if (vf_info->rx_accept_mode & mask) { flags->update_rx_mode_config =3D 1; @@ -5164,13 +5182,20 @@ static void qed_iov_handle_trust_change(struct qed_= hwfn *hwfn) if (!vf_info->is_trusted_configured) { flags->rx_accept_filter &=3D ~mask; flags->tx_accept_filter &=3D ~mask; + params.accept_any_vlan =3D false; } =20 if (flags->update_rx_mode_config || flags->update_tx_mode_config || - params.update_ctl_frame_check) + params.update_ctl_frame_check || + params.update_accept_any_vlan_flg) { + DP_VERBOSE(hwfn, QED_MSG_IOV, + "vport update config for %s VF[abs 0x%x rel 0x%x]\n", + vf_info->is_trusted_configured ? "trusted" : "untrusted", + vf->abs_vf_id, vf->relative_vf_id); qed_sp_vport_update(hwfn, ¶ms, QED_SPQ_MODE_EBLOCK, NULL); + } } } =20 diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.h b/drivers/net/ethe= rnet/qlogic/qed/qed_sriov.h index f448e3dd6c8b..6ee2493de164 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.h @@ -62,6 +62,7 @@ struct qed_public_vf_info { bool is_trusted_request; u8 rx_accept_mode; u8 tx_accept_mode; + bool accept_any_vlan; }; =20 struct qed_iov_vf_init_params { diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h b/drivers/net/= ethernet/qlogic/qlcnic/qlcnic_dcb.h index 5d79ee4370bc..7519773eaca6 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h @@ -51,7 +51,7 @@ static inline int qlcnic_dcb_get_hw_capability(struct qlc= nic_dcb *dcb) if (dcb && dcb->ops->get_hw_capability) return dcb->ops->get_hw_capability(dcb); =20 - return 0; + return -EOPNOTSUPP; } =20 static inline void qlcnic_dcb_free(struct qlcnic_dcb *dcb) @@ -65,7 +65,7 @@ static inline int qlcnic_dcb_attach(struct qlcnic_dcb *dc= b) if (dcb && dcb->ops->attach) return dcb->ops->attach(dcb); =20 - return 0; + return -EOPNOTSUPP; } =20 static inline int @@ -74,7 +74,7 @@ qlcnic_dcb_query_hw_capability(struct qlcnic_dcb *dcb, ch= ar *buf) if (dcb && dcb->ops->query_hw_capability) return dcb->ops->query_hw_capability(dcb, buf); =20 - return 0; + return -EOPNOTSUPP; } =20 static inline void qlcnic_dcb_get_info(struct qlcnic_dcb *dcb) @@ -89,7 +89,7 @@ qlcnic_dcb_query_cee_param(struct qlcnic_dcb *dcb, char *= buf, u8 type) if (dcb && dcb->ops->query_cee_param) return dcb->ops->query_cee_param(dcb, buf, type); =20 - return 0; + return -EOPNOTSUPP; } =20 static inline int qlcnic_dcb_get_cee_cfg(struct qlcnic_dcb *dcb) @@ -97,7 +97,7 @@ static inline int qlcnic_dcb_get_cee_cfg(struct qlcnic_dc= b *dcb) if (dcb && dcb->ops->get_cee_cfg) return dcb->ops->get_cee_cfg(dcb); =20 - return 0; + return -EOPNOTSUPP; } =20 static inline void qlcnic_dcb_aen_handler(struct qlcnic_dcb *dcb, void *ms= g) diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/s= unhme.c index ad9029ae6848..77e5dffb558f 100644 --- a/drivers/net/ethernet/sun/sunhme.c +++ b/drivers/net/ethernet/sun/sunhme.c @@ -3146,7 +3146,7 @@ static int happy_meal_pci_probe(struct pci_dev *pdev, if (err) { printk(KERN_ERR "happymeal(PCI): Cannot register net device, " "aborting.\n"); - goto err_out_iounmap; + goto err_out_free_coherent; } =20 pci_set_drvdata(pdev, hp); @@ -3179,6 +3179,10 @@ static int happy_meal_pci_probe(struct pci_dev *pdev, =20 return 0; =20 +err_out_free_coherent: + dma_free_coherent(hp->dma_dev, PAGE_SIZE, + hp->happy_block, hp->hblock_dvma); + err_out_iounmap: iounmap(hp->gregs); =20 diff --git a/drivers/net/ethernet/ti/cpsw_ethtool.c b/drivers/net/ethernet/= ti/cpsw_ethtool.c index 158c8d3793f4..b5bae6324970 100644 --- a/drivers/net/ethernet/ti/cpsw_ethtool.c +++ b/drivers/net/ethernet/ti/cpsw_ethtool.c @@ -364,11 +364,9 @@ int cpsw_ethtool_op_begin(struct net_device *ndev) struct cpsw_common *cpsw =3D priv->cpsw; int ret; =20 - ret =3D pm_runtime_get_sync(cpsw->dev); - if (ret < 0) { + ret =3D pm_runtime_resume_and_get(cpsw->dev); + if (ret < 0) cpsw_err(priv, drv, "ethtool begin failed %d\n", ret); - pm_runtime_put_noidle(cpsw->dev); - } =20 return ret; } diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/ne= t/ethernet/xilinx/xilinx_axienet_main.c index f12eb5beaded..0e066f2432dc 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -857,46 +857,53 @@ static void axienet_recv(struct net_device *ndev) while ((cur_p->status & XAXIDMA_BD_STS_COMPLETE_MASK)) { dma_addr_t phys; =20 - tail_p =3D lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci; - /* Ensure we see complete descriptor update */ dma_rmb(); - phys =3D desc_get_phys_addr(lp, cur_p); - dma_unmap_single(ndev->dev.parent, phys, lp->max_frm_size, - DMA_FROM_DEVICE); =20 skb =3D cur_p->skb; cur_p->skb =3D NULL; - length =3D cur_p->app4 & 0x0000FFFF; - - skb_put(skb, length); - skb->protocol =3D eth_type_trans(skb, ndev); - /*skb_checksum_none_assert(skb);*/ - skb->ip_summed =3D CHECKSUM_NONE; - - /* if we're doing Rx csum offload, set it up */ - if (lp->features & XAE_FEATURE_FULL_RX_CSUM) { - csumstatus =3D (cur_p->app2 & - XAE_FULL_CSUM_STATUS_MASK) >> 3; - if ((csumstatus =3D=3D XAE_IP_TCP_CSUM_VALIDATED) || - (csumstatus =3D=3D XAE_IP_UDP_CSUM_VALIDATED)) { - skb->ip_summed =3D CHECKSUM_UNNECESSARY; + + /* skb could be NULL if a previous pass already received the + * packet for this slot in the ring, but failed to refill it + * with a newly allocated buffer. In this case, don't try to + * receive it again. + */ + if (likely(skb)) { + length =3D cur_p->app4 & 0x0000FFFF; + + phys =3D desc_get_phys_addr(lp, cur_p); + dma_unmap_single(ndev->dev.parent, phys, lp->max_frm_size, + DMA_FROM_DEVICE); + + skb_put(skb, length); + skb->protocol =3D eth_type_trans(skb, ndev); + /*skb_checksum_none_assert(skb);*/ + skb->ip_summed =3D CHECKSUM_NONE; + + /* if we're doing Rx csum offload, set it up */ + if (lp->features & XAE_FEATURE_FULL_RX_CSUM) { + csumstatus =3D (cur_p->app2 & + XAE_FULL_CSUM_STATUS_MASK) >> 3; + if (csumstatus =3D=3D XAE_IP_TCP_CSUM_VALIDATED || + csumstatus =3D=3D XAE_IP_UDP_CSUM_VALIDATED) { + skb->ip_summed =3D CHECKSUM_UNNECESSARY; + } + } else if ((lp->features & XAE_FEATURE_PARTIAL_RX_CSUM) !=3D 0 && + skb->protocol =3D=3D htons(ETH_P_IP) && + skb->len > 64) { + skb->csum =3D be32_to_cpu(cur_p->app3 & 0xFFFF); + skb->ip_summed =3D CHECKSUM_COMPLETE; } - } else if ((lp->features & XAE_FEATURE_PARTIAL_RX_CSUM) !=3D 0 && - skb->protocol =3D=3D htons(ETH_P_IP) && - skb->len > 64) { - skb->csum =3D be32_to_cpu(cur_p->app3 & 0xFFFF); - skb->ip_summed =3D CHECKSUM_COMPLETE; - } =20 - netif_rx(skb); + netif_rx(skb); =20 - size +=3D length; - packets++; + size +=3D length; + packets++; + } =20 new_skb =3D netdev_alloc_skb_ip_align(ndev, lp->max_frm_size); if (!new_skb) - return; + break; =20 phys =3D dma_map_single(ndev->dev.parent, new_skb->data, lp->max_frm_size, @@ -905,7 +912,7 @@ static void axienet_recv(struct net_device *ndev) if (net_ratelimit()) netdev_err(ndev, "RX DMA mapping error\n"); dev_kfree_skb(new_skb); - return; + break; } desc_set_phys_addr(lp, phys, cur_p); =20 @@ -913,6 +920,11 @@ static void axienet_recv(struct net_device *ndev) cur_p->status =3D 0; cur_p->skb =3D new_skb; =20 + /* Only update tail_p to mark this slot as usable after it has + * been successfully refilled. + */ + tail_p =3D lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci; + if (++lp->rx_bd_ci >=3D lp->rx_bd_num) lp->rx_bd_ci =3D 0; cur_p =3D &lp->rx_bd_v[lp->rx_bd_ci]; diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index 32eeed672861..7e0f817d817f 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -784,25 +784,7 @@ static int at803x_probe(struct phy_device *phydev) return ret; } =20 - /* Some bootloaders leave the fiber page selected. - * Switch to the copper page, as otherwise we read - * the PHY capabilities from the fiber side. - */ - if (phydev->drv->phy_id =3D=3D ATH8031_PHY_ID) { - phy_lock_mdio_bus(phydev); - ret =3D at803x_write_page(phydev, AT803X_PAGE_COPPER); - phy_unlock_mdio_bus(phydev); - if (ret) - goto err; - } - return 0; - -err: - if (priv->vddio) - regulator_disable(priv->vddio); - - return ret; } =20 static void at803x_remove(struct phy_device *phydev) @@ -912,6 +894,22 @@ static int at803x_config_init(struct phy_device *phyde= v) { int ret; =20 + if (phydev->drv->phy_id =3D=3D ATH8031_PHY_ID) { + /* Some bootloaders leave the fiber page selected. + * Switch to the copper page, as otherwise we read + * the PHY capabilities from the fiber side. + */ + phy_lock_mdio_bus(phydev); + ret =3D at803x_write_page(phydev, AT803X_PAGE_COPPER); + phy_unlock_mdio_bus(phydev); + if (ret) + return ret; + + ret =3D at8031_pll_config(phydev); + if (ret < 0) + return ret; + } + /* The RX and TX delay default is: * after HW reset: RX delay enabled and TX delay disabled * after SW reset: RX delay enabled, while TX delay retains the @@ -941,12 +939,6 @@ static int at803x_config_init(struct phy_device *phyde= v) if (ret < 0) return ret; =20 - if (phydev->drv->phy_id =3D=3D ATH8031_PHY_ID) { - ret =3D at8031_pll_config(phydev); - if (ret < 0) - return ret; - } - /* Ar803x extended next page bit is enabled by default. Cisco * multigig switches read this bit and attempt to negotiate 10Gbps * rates even if the next page bit is disabled. This is incorrect diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 3c683e0e40e9..e36809aa6d30 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -11,6 +11,7 @@ */ =20 #include "bcm-phy-lib.h" +#include #include #include #include @@ -602,6 +603,26 @@ static int brcm_fet_config_init(struct phy_device *phy= dev) if (err < 0) return err; =20 + /* The datasheet indicates the PHY needs up to 1us to complete a reset, + * build some slack here. + */ + usleep_range(1000, 2000); + + /* The PHY requires 65 MDC clock cycles to complete a write operation + * and turnaround the line properly. + * + * We ignore -EIO here as the MDIO controller (e.g.: mdio-bcm-unimac) + * may flag the lack of turn-around as a read failure. This is + * particularly true with this combination since the MDIO controller + * only used 64 MDC cycles. This is not a critical failure in this + * specific case and it has no functional impact otherwise, so we let + * that one go through. If there is a genuine bus error, the next read + * of MII_BRCM_FET_INTREG will error out. + */ + err =3D phy_read(phydev, MII_BMCR); + if (err < 0 && err !=3D -EIO) + return err; + reg =3D phy_read(phydev, MII_BRCM_FET_INTREG); if (reg < 0) return reg; diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 76ef4e019ca9..15fe0fa78092 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -1575,11 +1575,13 @@ static int lanphy_read_page_reg(struct phy_device *= phydev, int page, u32 addr) { u32 data; =20 - phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL, page); - phy_write(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA, addr); - phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL, - (page | LAN_EXT_PAGE_ACCESS_CTRL_EP_FUNC)); - data =3D phy_read(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA); + phy_lock_mdio_bus(phydev); + __phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL, page); + __phy_write(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA, addr); + __phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL, + (page | LAN_EXT_PAGE_ACCESS_CTRL_EP_FUNC)); + data =3D __phy_read(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA); + phy_unlock_mdio_bus(phydev); =20 return data; } @@ -1587,18 +1589,18 @@ static int lanphy_read_page_reg(struct phy_device *= phydev, int page, u32 addr) static int lanphy_write_page_reg(struct phy_device *phydev, int page, u16 = addr, u16 val) { - phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL, page); - phy_write(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA, addr); - phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL, - (page | LAN_EXT_PAGE_ACCESS_CTRL_EP_FUNC)); - - val =3D phy_write(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA, val); - if (val) { + phy_lock_mdio_bus(phydev); + __phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL, page); + __phy_write(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA, addr); + __phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL, + page | LAN_EXT_PAGE_ACCESS_CTRL_EP_FUNC); + + val =3D __phy_write(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA, val); + if (val !=3D 0) phydev_err(phydev, "Error: phy_write has returned error %d\n", val); - return val; - } - return 0; + phy_unlock_mdio_bus(phydev); + return val; } =20 static int lan8804_config_init(struct phy_device *phydev) diff --git a/drivers/net/usb/asix.h b/drivers/net/usb/asix.h index 2a1e31defe71..4334aafab59a 100644 --- a/drivers/net/usb/asix.h +++ b/drivers/net/usb/asix.h @@ -192,8 +192,8 @@ extern const struct driver_info ax88172a_info; /* ASIX specific flags */ #define FLAG_EEPROM_MAC (1UL << 0) /* init device MAC from eeprom */ =20 -int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data, int in_pm); +int __must_check asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 = index, + u16 size, void *data, int in_pm); =20 int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, u16 size, void *data, int in_pm); diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index 71682970be58..524805285019 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c @@ -11,8 +11,8 @@ =20 #define AX_HOST_EN_RETRIES 30 =20 -int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data, int in_pm) +int __must_check asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 = index, + u16 size, void *data, int in_pm) { int ret; int (*fn)(struct usbnet *, u8, u8, u16, u16, void *, u16); @@ -27,9 +27,12 @@ int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value,= u16 index, ret =3D fn(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, data, size); =20 - if (unlikely(ret < 0)) + if (unlikely(ret < size)) { + ret =3D ret < 0 ? ret : -ENODATA; + netdev_warn(dev->net, "Failed to read reg index 0x%04x: %d\n", index, ret); + } =20 return ret; } @@ -79,7 +82,7 @@ static int asix_check_host_enable(struct usbnet *dev, int= in_pm) 0, 0, 1, &smsr, in_pm); if (ret =3D=3D -ENODEV) break; - else if (ret < sizeof(smsr)) + else if (ret < 0) continue; else if (smsr & AX_HOST_EN) break; @@ -579,8 +582,12 @@ int asix_mdio_read_nopm(struct net_device *netdev, int= phy_id, int loc) return ret; } =20 - asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, - (__u16)loc, 2, &res, 1); + ret =3D asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, + (__u16)loc, 2, &res, 1); + if (ret < 0) { + mutex_unlock(&dev->phy_mutex); + return ret; + } asix_set_hw_mii(dev, 1); mutex_unlock(&dev->phy_mutex); =20 diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 4514d35ef4c4..6b2fbdf4e0fd 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -755,7 +755,12 @@ static int ax88772_bind(struct usbnet *dev, struct usb= _interface *intf) priv->phy_addr =3D ret; priv->embd_phy =3D ((priv->phy_addr & 0x1f) =3D=3D 0x10); =20 - asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, 0, 0, 1, &chipcode, 0); + ret =3D asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, 0, 0, 1, &chipcode, 0); + if (ret < 0) { + netdev_dbg(dev->net, "Failed to read STATMNGSTS_REG: %d\n", ret); + return ret; + } + chipcode &=3D AX_CHIPCODE_MASK; =20 ret =3D (chipcode =3D=3D AX_AX88772_CHIPCODE) ? ax88772_hw_reset(dev, 0) : @@ -920,11 +925,21 @@ static int ax88178_reset(struct usbnet *dev) int gpio0 =3D 0; u32 phyid; =20 - asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status, 0); + ret =3D asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status, 0); + if (ret < 0) { + netdev_dbg(dev->net, "Failed to read GPIOS: %d\n", ret); + return ret; + } + netdev_dbg(dev->net, "GPIO Status: 0x%04x\n", status); =20 asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL, 0); - asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom, 0); + ret =3D asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom, 0); + if (ret < 0) { + netdev_dbg(dev->net, "Failed to read EEPROM: %d\n", ret); + return ret; + } + asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL, 0); =20 netdev_dbg(dev->net, "EEPROM index 0x17 is 0x%04x\n", eeprom); diff --git a/drivers/net/wireguard/queueing.c b/drivers/net/wireguard/queue= ing.c index 1de413b19e34..8084e7408c0a 100644 --- a/drivers/net/wireguard/queueing.c +++ b/drivers/net/wireguard/queueing.c @@ -4,6 +4,7 @@ */ =20 #include "queueing.h" +#include =20 struct multicore_worker __percpu * wg_packet_percpu_multicore_worker_alloc(work_func_t function, void *ptr) @@ -42,7 +43,7 @@ void wg_packet_queue_free(struct crypt_queue *queue, bool= purge) { free_percpu(queue->worker); WARN_ON(!purge && !__ptr_ring_empty(&queue->ring)); - ptr_ring_cleanup(&queue->ring, purge ? (void(*)(void*))kfree_skb : NULL); + ptr_ring_cleanup(&queue->ring, purge ? __skb_array_destroy_skb : NULL); } =20 #define NEXT(skb) ((skb)->prev) diff --git a/drivers/net/wireguard/socket.c b/drivers/net/wireguard/socket.c index 6f07b949cb81..0414d7a6ce74 100644 --- a/drivers/net/wireguard/socket.c +++ b/drivers/net/wireguard/socket.c @@ -160,6 +160,7 @@ static int send6(struct wg_device *wg, struct sk_buff *= skb, rcu_read_unlock_bh(); return ret; #else + kfree_skb(skb); return -EAFNOSUPPORT; #endif } @@ -241,7 +242,7 @@ int wg_socket_endpoint_from_skb(struct endpoint *endpoi= nt, endpoint->addr4.sin_addr.s_addr =3D ip_hdr(skb)->saddr; endpoint->src4.s_addr =3D ip_hdr(skb)->daddr; endpoint->src_if4 =3D skb->skb_iif; - } else if (skb->protocol =3D=3D htons(ETH_P_IPV6)) { + } else if (IS_ENABLED(CONFIG_IPV6) && skb->protocol =3D=3D htons(ETH_P_IP= V6)) { endpoint->addr6.sin6_family =3D AF_INET6; endpoint->addr6.sin6_port =3D udp_hdr(skb)->source; endpoint->addr6.sin6_addr =3D ipv6_hdr(skb)->saddr; @@ -284,7 +285,7 @@ void wg_socket_set_peer_endpoint(struct wg_peer *peer, peer->endpoint.addr4 =3D endpoint->addr4; peer->endpoint.src4 =3D endpoint->src4; peer->endpoint.src_if4 =3D endpoint->src_if4; - } else if (endpoint->addr.sa_family =3D=3D AF_INET6) { + } else if (IS_ENABLED(CONFIG_IPV6) && endpoint->addr.sa_family =3D=3D AF_= INET6) { peer->endpoint.addr6 =3D endpoint->addr6; peer->endpoint.src6 =3D endpoint->src6; } else { diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/= ath/ath10k/snoc.c index 9513ab696fff..f79dd9a71690 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -1556,11 +1556,11 @@ static int ath10k_setup_msa_resources(struct ath10k= *ar, u32 msa_size) node =3D of_parse_phandle(dev->of_node, "memory-region", 0); if (node) { ret =3D of_address_to_resource(node, 0, &r); + of_node_put(node); if (ret) { dev_err(dev, "failed to resolve msa fixed region\n"); return ret; } - of_node_put(node); =20 ar->msa.paddr =3D r.start; ar->msa.mem_size =3D resource_size(&r); diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/a= th/ath10k/wow.c index 7d65c115669f..20b9aa8ddf7d 100644 --- a/drivers/net/wireless/ath/ath10k/wow.c +++ b/drivers/net/wireless/ath/ath10k/wow.c @@ -337,14 +337,15 @@ static int ath10k_vif_wow_set_wakeups(struct ath10k_v= if *arvif, if (patterns[i].mask[j / 8] & BIT(j % 8)) bitmask[j] =3D 0xff; old_pattern.mask =3D bitmask; - new_pattern =3D old_pattern; =20 if (ar->wmi.rx_decap_mode =3D=3D ATH10K_HW_TXRX_NATIVE_WIFI) { - if (patterns[i].pkt_offset < ETH_HLEN) + if (patterns[i].pkt_offset < ETH_HLEN) { ath10k_wow_convert_8023_to_80211(&new_pattern, &old_pattern); - else + } else { + new_pattern =3D old_pattern; new_pattern.pkt_offset +=3D WOW_HDR_LEN - ETH_HLEN; + } } =20 if (WARN_ON(new_pattern.pattern_len > WOW_MAX_PATTERN_SIZE)) diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless= /ath/ath11k/dp_rx.c index 621372c568d2..38102617c342 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -2596,13 +2596,11 @@ static int ath11k_dp_rx_process_msdu(struct ath11k = *ar, static void ath11k_dp_rx_process_received_packets(struct ath11k_base *ab, struct napi_struct *napi, struct sk_buff_head *msdu_list, - int *quota, int ring_id) + int *quota, int mac_id) { - struct ath11k_skb_rxcb *rxcb; struct sk_buff *msdu; struct ath11k *ar; struct ieee80211_rx_status rx_status =3D {0}; - u8 mac_id; int ret; =20 if (skb_queue_empty(msdu_list)) @@ -2610,20 +2608,20 @@ static void ath11k_dp_rx_process_received_packets(s= truct ath11k_base *ab, =20 rcu_read_lock(); =20 - while (*quota && (msdu =3D __skb_dequeue(msdu_list))) { - rxcb =3D ATH11K_SKB_RXCB(msdu); - mac_id =3D rxcb->mac_id; - ar =3D ab->pdevs[mac_id].ar; - if (!rcu_dereference(ab->pdevs_active[mac_id])) { - dev_kfree_skb_any(msdu); - continue; - } + ar =3D ab->pdevs[mac_id].ar; + if (!rcu_dereference(ab->pdevs_active[mac_id])) { + __skb_queue_purge(msdu_list); + rcu_read_unlock(); + return; + } =20 - if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) { - dev_kfree_skb_any(msdu); - continue; - } + if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) { + __skb_queue_purge(msdu_list); + rcu_read_unlock(); + return; + } =20 + while ((msdu =3D __skb_dequeue(msdu_list))) { ret =3D ath11k_dp_rx_process_msdu(ar, msdu, msdu_list, &rx_status); if (ret) { ath11k_dbg(ab, ATH11K_DBG_DATA, @@ -2645,7 +2643,7 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int = ring_id, struct ath11k_dp *dp =3D &ab->dp; struct dp_rxdma_ring *rx_ring; int num_buffs_reaped[MAX_RADIOS] =3D {0}; - struct sk_buff_head msdu_list; + struct sk_buff_head msdu_list[MAX_RADIOS]; struct ath11k_skb_rxcb *rxcb; int total_msdu_reaped =3D 0; struct hal_srng *srng; @@ -2654,25 +2652,26 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, in= t ring_id, bool done =3D false; int buf_id, mac_id; struct ath11k *ar; - u32 *rx_desc; + struct hal_reo_dest_ring *desc; + enum hal_reo_dest_ring_push_reason push_reason; + u32 cookie; int i; =20 - __skb_queue_head_init(&msdu_list); + for (i =3D 0; i < MAX_RADIOS; i++) + __skb_queue_head_init(&msdu_list[i]); =20 srng =3D &ab->hal.srng_list[dp->reo_dst_ring[ring_id].ring_id]; =20 spin_lock_bh(&srng->lock); =20 - ath11k_hal_srng_access_begin(ab, srng); - try_again: - while ((rx_desc =3D ath11k_hal_srng_dst_get_next_entry(ab, srng))) { - struct hal_reo_dest_ring desc =3D *(struct hal_reo_dest_ring *)rx_desc; - enum hal_reo_dest_ring_push_reason push_reason; - u32 cookie; + ath11k_hal_srng_access_begin(ab, srng); =20 + while (likely(desc =3D + (struct hal_reo_dest_ring *)ath11k_hal_srng_dst_get_next_entry(ab, + srng))) { cookie =3D FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, - desc.buf_addr_info.info1); + desc->buf_addr_info.info1); buf_id =3D FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, cookie); mac_id =3D FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, cookie); @@ -2700,7 +2699,7 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int = ring_id, total_msdu_reaped++; =20 push_reason =3D FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON, - desc.info0); + desc->info0); if (push_reason !=3D HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) { dev_kfree_skb_any(msdu); @@ -2708,21 +2707,21 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, in= t ring_id, continue; } =20 - rxcb->is_first_msdu =3D !!(desc.rx_msdu_info.info0 & + rxcb->is_first_msdu =3D !!(desc->rx_msdu_info.info0 & RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU); - rxcb->is_last_msdu =3D !!(desc.rx_msdu_info.info0 & + rxcb->is_last_msdu =3D !!(desc->rx_msdu_info.info0 & RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU); - rxcb->is_continuation =3D !!(desc.rx_msdu_info.info0 & + rxcb->is_continuation =3D !!(desc->rx_msdu_info.info0 & RX_MSDU_DESC_INFO0_MSDU_CONTINUATION); rxcb->peer_id =3D FIELD_GET(RX_MPDU_DESC_META_DATA_PEER_ID, - desc.rx_mpdu_info.meta_data); + desc->rx_mpdu_info.meta_data); rxcb->seq_no =3D FIELD_GET(RX_MPDU_DESC_INFO0_SEQ_NUM, - desc.rx_mpdu_info.info0); + desc->rx_mpdu_info.info0); rxcb->tid =3D FIELD_GET(HAL_REO_DEST_RING_INFO0_RX_QUEUE_NUM, - desc.info0); + desc->info0); =20 rxcb->mac_id =3D mac_id; - __skb_queue_tail(&msdu_list, msdu); + __skb_queue_tail(&msdu_list[mac_id], msdu); =20 if (total_msdu_reaped >=3D quota && !rxcb->is_continuation) { done =3D true; @@ -2752,16 +2751,15 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, in= t ring_id, if (!num_buffs_reaped[i]) continue; =20 + ath11k_dp_rx_process_received_packets(ab, napi, &msdu_list[i], + "a, i); + ar =3D ab->pdevs[i].ar; rx_ring =3D &ar->dp.rx_refill_buf_ring; =20 ath11k_dp_rxbufs_replenish(ab, i, rx_ring, num_buffs_reaped[i], ab->hw_params.hal_params->rx_buf_rbm); } - - ath11k_dp_rx_process_received_packets(ab, napi, &msdu_list, - "a, ring_id); - exit: return budget - quota; } diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/a= th/ath11k/mac.c index a7400ade7a0c..8d8eae438567 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -2039,6 +2039,9 @@ static void ath11k_peer_assoc_h_he_6ghz(struct ath11k= *ar, if (!arg->he_flag || band !=3D NL80211_BAND_6GHZ || !sta->he_6ghz_capa.ca= pa) return; =20 + if (sta->bandwidth =3D=3D IEEE80211_STA_RX_BW_40) + arg->bw_40 =3D true; + if (sta->bandwidth =3D=3D IEEE80211_STA_RX_BW_80) arg->bw_80 =3D true; =20 diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireles= s/ath/ath9k/htc_hst.c index 510e61e97dbc..994ec48b2f66 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -30,6 +30,7 @@ static int htc_issue_send(struct htc_target *target, stru= ct sk_buff* skb, hdr->endpoint_id =3D epid; hdr->flags =3D flags; hdr->payload_len =3D cpu_to_be16(len); + memset(hdr->control, 0, sizeof(hdr->control)); =20 status =3D target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb); =20 @@ -272,6 +273,10 @@ int htc_connect_service(struct htc_target *target, conn_msg->dl_pipeid =3D endpoint->dl_pipeid; conn_msg->ul_pipeid =3D endpoint->ul_pipeid; =20 + /* To prevent infoleak */ + conn_msg->svc_meta_len =3D 0; + conn_msg->pad =3D 0; + ret =3D htc_issue_send(target, skb, skb->len, 0, ENDPOINT0); if (ret) goto err; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireles= s/ath/carl9170/main.c index cca3b086aa70..a87476383c54 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1915,7 +1915,7 @@ static int carl9170_parse_eeprom(struct ar9170 *ar) WARN_ON(!(tx_streams >=3D 1 && tx_streams <=3D IEEE80211_HT_MCS_TX_MAX_STREAMS)); =20 - tx_params =3D (tx_streams - 1) << + tx_params |=3D (tx_streams - 1) << IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; =20 carl9170_band_2GHz.ht_cap.mcs.tx_params |=3D tx_params; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/= drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c index d99140960a82..dcbe55b56e43 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c @@ -207,6 +207,8 @@ static int brcmf_init_nvram_parser(struct nvram_parser = *nvp, size =3D BRCMF_FW_MAX_NVRAM_SIZE; else size =3D data_len; + /* Add space for properties we may add */ + size +=3D strlen(BRCMF_FW_DEFAULT_BOARDREV) + 1; /* Alloc for extra 0 byte + roundup by 4 + length field */ size +=3D 1 + 3 + sizeof(u32); nvp->nvram =3D kzalloc(size, GFP_KERNEL); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/driv= ers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 8b149996fc00..3ff4997e1c97 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -12,6 +12,7 @@ #include #include #include +#include #include =20 #include @@ -59,6 +60,13 @@ BRCMF_FW_DEF(4366B, "brcmfmac4366b-pcie"); BRCMF_FW_DEF(4366C, "brcmfmac4366c-pcie"); BRCMF_FW_DEF(4371, "brcmfmac4371-pcie"); =20 +/* firmware config files */ +MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.txt"); +MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.txt"); + +/* per-board firmware binaries */ +MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.bin"); + static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] =3D { BRCMF_FW_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602), BRCMF_FW_ENTRY(BRCM_CC_43465_CHIP_ID, 0xFFFFFFF0, 4366C), @@ -447,47 +455,6 @@ brcmf_pcie_write_ram32(struct brcmf_pciedev_info *devi= nfo, u32 mem_offset, } =20 =20 -static void -brcmf_pcie_copy_mem_todev(struct brcmf_pciedev_info *devinfo, u32 mem_offs= et, - void *srcaddr, u32 len) -{ - void __iomem *address =3D devinfo->tcm + mem_offset; - __le32 *src32; - __le16 *src16; - u8 *src8; - - if (((ulong)address & 4) || ((ulong)srcaddr & 4) || (len & 4)) { - if (((ulong)address & 2) || ((ulong)srcaddr & 2) || (len & 2)) { - src8 =3D (u8 *)srcaddr; - while (len) { - iowrite8(*src8, address); - address++; - src8++; - len--; - } - } else { - len =3D len / 2; - src16 =3D (__le16 *)srcaddr; - while (len) { - iowrite16(le16_to_cpu(*src16), address); - address +=3D 2; - src16++; - len--; - } - } - } else { - len =3D len / 4; - src32 =3D (__le32 *)srcaddr; - while (len) { - iowrite32(le32_to_cpu(*src32), address); - address +=3D 4; - src32++; - len--; - } - } -} - - static void brcmf_pcie_copy_dev_tomem(struct brcmf_pciedev_info *devinfo, u32 mem_offs= et, void *dstaddr, u32 len) @@ -1348,6 +1315,18 @@ static void brcmf_pcie_down(struct device *dev) { } =20 +static int brcmf_pcie_preinit(struct device *dev) +{ + struct brcmf_bus *bus_if =3D dev_get_drvdata(dev); + struct brcmf_pciedev *buspub =3D bus_if->bus_priv.pcie; + + brcmf_dbg(PCIE, "Enter\n"); + + brcmf_pcie_intr_enable(buspub->devinfo); + brcmf_pcie_hostready(buspub->devinfo); + + return 0; +} =20 static int brcmf_pcie_tx(struct device *dev, struct sk_buff *skb) { @@ -1456,6 +1435,7 @@ static int brcmf_pcie_reset(struct device *dev) } =20 static const struct brcmf_bus_ops brcmf_pcie_bus_ops =3D { + .preinit =3D brcmf_pcie_preinit, .txdata =3D brcmf_pcie_tx, .stop =3D brcmf_pcie_down, .txctl =3D brcmf_pcie_tx_ctlpkt, @@ -1563,8 +1543,8 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_= pciedev_info *devinfo, return err; =20 brcmf_dbg(PCIE, "Download FW %s\n", devinfo->fw_name); - brcmf_pcie_copy_mem_todev(devinfo, devinfo->ci->rambase, - (void *)fw->data, fw->size); + memcpy_toio(devinfo->tcm + devinfo->ci->rambase, + (void *)fw->data, fw->size); =20 resetintr =3D get_unaligned_le32(fw->data); release_firmware(fw); @@ -1578,7 +1558,7 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_= pciedev_info *devinfo, brcmf_dbg(PCIE, "Download NVRAM %s\n", devinfo->nvram_name); address =3D devinfo->ci->rambase + devinfo->ci->ramsize - nvram_len; - brcmf_pcie_copy_mem_todev(devinfo, address, nvram, nvram_len); + memcpy_toio(devinfo->tcm + address, nvram, nvram_len); brcmf_fw_nvram_free(nvram); } else { brcmf_dbg(PCIE, "No matching NVRAM file found %s\n", @@ -1777,6 +1757,8 @@ static void brcmf_pcie_setup(struct device *dev, int = ret, ret =3D brcmf_chip_get_raminfo(devinfo->ci); if (ret) { brcmf_err(bus, "Failed to get RAM info\n"); + release_firmware(fw); + brcmf_fw_nvram_free(nvram); goto fail; } =20 @@ -1826,9 +1808,6 @@ static void brcmf_pcie_setup(struct device *dev, int = ret, =20 init_waitqueue_head(&devinfo->mbdata_resp_wait); =20 - brcmf_pcie_intr_enable(devinfo); - brcmf_pcie_hostready(devinfo); - ret =3D brcmf_attach(&devinfo->pdev->dev); if (ret) goto fail; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/driv= ers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 8effeb7a7269..5d156e591b35 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -629,7 +629,6 @@ BRCMF_FW_CLM_DEF(43752, "brcmfmac43752-sdio"); =20 /* firmware config files */ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-sdio.*.txt"); -MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.txt"); =20 /* per-board firmware binaries */ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-sdio.*.bin"); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/ne= t/wireless/intel/iwlwifi/dvm/mac80211.c index 754876cd27ce..e8bd4f0e3d2d 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c @@ -299,7 +299,7 @@ static int iwlagn_mac_start(struct ieee80211_hw *hw) =20 priv->is_open =3D 1; IWL_DEBUG_MAC80211(priv, "leave\n"); - return 0; + return ret; } =20 static void iwlagn_mac_stop(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wire= less/intel/iwlwifi/fw/dbg.c index a39013c401c9..e2001e88a4b4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1562,8 +1562,6 @@ iwl_dump_ini_dbgi_sram_iter(struct iwl_fw_runtime *fw= rt, return -EBUSY; =20 range->range_data_size =3D reg->dev_addr.size; - iwl_write_prph_no_grab(fwrt->trans, DBGI_SRAM_TARGET_ACCESS_CFG, - DBGI_SRAM_TARGET_ACCESS_CFG_RESET_ADDRESS_MSK); for (i =3D 0; i < (le32_to_cpu(reg->dev_addr.size) / 4); i++) { prph_data =3D iwl_read_prph(fwrt->trans, (i % 2) ? DBGI_SRAM_TARGET_ACCESS_RDATA_MSB : diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net= /wireless/intel/iwlwifi/iwl-dbg-tlv.c index 7ab98b419cc1..d412b6d0b28e 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -849,11 +849,18 @@ static void iwl_dbg_tlv_apply_config(struct iwl_fw_ru= ntime *fwrt, case IWL_FW_INI_CONFIG_SET_TYPE_DBGC_DRAM_ADDR: { struct iwl_dbgc1_info dram_info =3D {}; struct iwl_dram_data *frags =3D &fwrt->trans->dbg.fw_mon_ini[1].frags[0= ]; - __le64 dram_base_addr =3D cpu_to_le64(frags->physical); - __le32 dram_size =3D cpu_to_le32(frags->size); - u64 dram_addr =3D le64_to_cpu(dram_base_addr); + __le64 dram_base_addr; + __le32 dram_size; + u64 dram_addr; u32 ret; =20 + if (!frags) + break; + + dram_base_addr =3D cpu_to_le64(frags->physical); + dram_size =3D cpu_to_le32(frags->size); + dram_addr =3D le64_to_cpu(dram_base_addr); + IWL_DEBUG_FW(fwrt, "WRT: dram_base_addr 0x%016llx, dram_size 0x%x\n", dram_base_addr, dram_size); IWL_DEBUG_FW(fwrt, "WRT: config_list->addr_offset: %u\n", diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wi= reless/intel/iwlwifi/iwl-prph.h index a84ab02cf9d7..7d3fedfdb348 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -356,8 +356,6 @@ #define WFPM_GP2 0xA030B4 =20 /* DBGI SRAM Register details */ -#define DBGI_SRAM_TARGET_ACCESS_CFG 0x00A2E14C -#define DBGI_SRAM_TARGET_ACCESS_CFG_RESET_ADDRESS_MSK 0x10000 #define DBGI_SRAM_TARGET_ACCESS_RDATA_LSB 0x00A2E154 #define DBGI_SRAM_TARGET_ACCESS_RDATA_MSB 0x00A2E158 =20 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wire= less/intel/iwlwifi/mvm/d3.c index a19f646a324f..75e9776001b8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -2566,7 +2566,9 @@ static int iwl_mvm_d3_test_open(struct inode *inode, = struct file *file) =20 /* start pseudo D3 */ rtnl_lock(); + wiphy_lock(mvm->hw->wiphy); err =3D __iwl_mvm_suspend(mvm->hw, mvm->hw->wiphy->wowlan_config, true); + wiphy_unlock(mvm->hw->wiphy); rtnl_unlock(); if (err > 0) err =3D -EINVAL; @@ -2622,7 +2624,9 @@ static int iwl_mvm_d3_test_release(struct inode *inod= e, struct file *file) iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt); =20 rtnl_lock(); + wiphy_lock(mvm->hw->wiphy); __iwl_mvm_resume(mvm, true); + wiphy_unlock(mvm->hw->wiphy); rtnl_unlock(); =20 iwl_mvm_resume_tcm(mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wire= less/intel/iwlwifi/mvm/fw.c index 58d5395acf73..6d17d7a71182 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1553,8 +1553,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm) while (!sband && i < NUM_NL80211_BANDS) sband =3D mvm->hw->wiphy->bands[i++]; =20 - if (WARN_ON_ONCE(!sband)) + if (WARN_ON_ONCE(!sband)) { + ret =3D -ENODEV; goto error; + } =20 chan =3D &sband->channels[0]; =20 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wir= eless/intel/iwlwifi/mvm/ops.c index 364f6aefae81..5b7d89e33431 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -237,7 +237,8 @@ static void iwl_mvm_rx_thermal_dual_chain_req(struct iw= l_mvm *mvm, */ mvm->fw_static_smps_request =3D req->event =3D=3D cpu_to_le32(THERMAL_DUAL_CHAIN_REQ_DISABLE); - ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, + ieee80211_iterate_interfaces(mvm->hw, + IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER, iwl_mvm_intf_dual_chain_req, NULL); } =20 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wire= less/intel/iwlwifi/mvm/tx.c index 0f96d422d6e0..bbd394a7b531 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -272,15 +272,14 @@ static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm, =20 /* info->control is only relevant for non HW rate control */ if (!ieee80211_hw_check(mvm->hw, HAS_RATE_CONTROL)) { - struct iwl_mvm_sta *mvmsta =3D iwl_mvm_sta_from_mac80211(sta); - /* HT rate doesn't make sense for a non data frame */ WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS && !ieee80211_is_data(fc), "Got a HT rate (flags:0x%x/mcs:%d/fc:0x%x/state:%d) for a non data fr= ame\n", info->control.rates[0].flags, info->control.rates[0].idx, - le16_to_cpu(fc), sta ? mvmsta->sta_state : -1); + le16_to_cpu(fc), + sta ? iwl_mvm_sta_from_mac80211(sta)->sta_state : -1); =20 rate_idx =3D info->control.rates[0].idx; } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/= wireless/intel/iwlwifi/pcie/trans.c index 3b38c426575b..39cd7dfea78f 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1084,7 +1084,7 @@ static const struct iwl_causes_list causes_list_pre_b= z[] =3D { }; =20 static const struct iwl_causes_list causes_list_bz[] =3D { - {MSIX_HW_INT_CAUSES_REG_SW_ERR_BZ, CSR_MSIX_HW_INT_MASK_AD, 0x29}, + {MSIX_HW_INT_CAUSES_REG_SW_ERR_BZ, CSR_MSIX_HW_INT_MASK_AD, 0x15}, }; =20 static void iwl_pcie_map_list(struct iwl_trans *trans, diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net= /wireless/mediatek/mt76/mt7603/main.c index 7ac4cd247a73..689fcee282b3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -623,6 +623,9 @@ mt7603_sta_rate_tbl_update(struct ieee80211_hw *hw, str= uct ieee80211_vif *vif, struct ieee80211_sta_rates *sta_rates =3D rcu_dereference(sta->rates); int i; =20 + if (!sta_rates) + return; + spin_lock_bh(&dev->mt76.lock); for (i =3D 0; i < ARRAY_SIZE(msta->rates); i++) { msta->rates[i].idx =3D sta_rates->rate[i].idx; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/= wireless/mediatek/mt76/mt7615/mac.c index c79abce543f3..ed8f7bc18977 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -2000,6 +2000,14 @@ void mt7615_pm_power_save_work(struct work_struct *w= ork) test_bit(MT76_HW_SCHED_SCANNING, &dev->mphy.state)) goto out; =20 + if (mutex_is_locked(&dev->mt76.mutex)) + /* if mt76 mutex is held we should not put the device + * to sleep since we are currently accessing device + * register map. We need to wait for the next power_save + * trigger. + */ + goto out; + if (time_is_after_jiffies(dev->pm.last_activity + delta)) { delta =3D dev->pm.last_activity + delta - jiffies; goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net= /wireless/mediatek/mt76/mt7615/main.c index 1fdcada157d6..18a320d00d8d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -686,6 +686,9 @@ static void mt7615_sta_rate_tbl_update(struct ieee80211= _hw *hw, struct ieee80211_sta_rates *sta_rates =3D rcu_dereference(sta->rates); int i; =20 + if (!sta_rates) + return; + spin_lock_bh(&dev->mt76.lock); for (i =3D 0; i < ARRAY_SIZE(msta->rates); i++) { msta->rates[i].idx =3D sta_rates->rate[i].idx; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers= /net/wireless/mediatek/mt76/mt76_connac_mcu.c index 1fb8432aa27c..6235ed3a332b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -313,7 +313,7 @@ mt76_connac_mcu_alloc_wtbl_req(struct mt76_dev *dev, st= ruct mt76_wcid *wcid, } =20 if (sta_hdr) - sta_hdr->len =3D cpu_to_le16(sizeof(hdr)); + le16_add_cpu(&sta_hdr->len, sizeof(hdr)); =20 return skb_put_data(nskb, &hdr, sizeof(hdr)); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers= /net/wireless/mediatek/mt76/mt76_connac_mcu.h index acb9a286d354..43a8b3651dc2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -598,7 +598,8 @@ enum { MCU_CE_CMD_SET_BSS_CONNECTED =3D 0x16, MCU_CE_CMD_SET_BSS_ABORT =3D 0x17, MCU_CE_CMD_CANCEL_HW_SCAN =3D 0x1b, - MCU_CE_CMD_SET_ROC =3D 0x1d, + MCU_CE_CMD_SET_ROC =3D 0x1c, + MCU_CE_CMD_SET_EDCA_PARMS =3D 0x1d, MCU_CE_CMD_SET_P2P_OPPPS =3D 0x33, MCU_CE_CMD_SET_RATE_TX_POWER =3D 0x5d, MCU_CE_CMD_SCHED_SCAN_ENABLE =3D 0x61, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/= wireless/mediatek/mt76/mt7915/mac.c index 38d66411444a..a1da514ca256 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1412,7 +1412,6 @@ mt7915_mac_add_txs_skb(struct mt7915_dev *dev, struct= mt76_wcid *wcid, int pid, break; case MT_PHY_TYPE_HT: case MT_PHY_TYPE_HT_GF: - rate.mcs +=3D (rate.nss - 1) * 8; if (rate.mcs > 31) goto out; =20 diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/= wireless/mediatek/mt76/mt7915/mcu.c index 8215b3d79bbd..5ea82f05fd91 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -211,24 +211,12 @@ mt7915_mcu_get_sta_nss(u16 mcs_map) =20 static void mt7915_mcu_set_sta_he_mcs(struct ieee80211_sta *sta, __le16 *he_mcs, - const u16 *mask) + u16 mcs_map) { struct mt7915_sta *msta =3D (struct mt7915_sta *)sta->drv_priv; - struct cfg80211_chan_def *chandef =3D &msta->vif->phy->mt76->chandef; + enum nl80211_band band =3D msta->vif->phy->mt76->chandef.chan->band; + const u16 *mask =3D msta->vif->bitrate_mask.control[band].he_mcs; int nss, max_nss =3D sta->rx_nss > 3 ? 4 : sta->rx_nss; - u16 mcs_map; - - switch (chandef->width) { - case NL80211_CHAN_WIDTH_80P80: - mcs_map =3D le16_to_cpu(sta->he_cap.he_mcs_nss_supp.rx_mcs_80p80); - break; - case NL80211_CHAN_WIDTH_160: - mcs_map =3D le16_to_cpu(sta->he_cap.he_mcs_nss_supp.rx_mcs_160); - break; - default: - mcs_map =3D le16_to_cpu(sta->he_cap.he_mcs_nss_supp.rx_mcs_80); - break; - } =20 for (nss =3D 0; nss < max_nss; nss++) { int mcs; @@ -1263,8 +1251,11 @@ mt7915_mcu_wtbl_generic_tlv(struct sk_buff *skb, str= uct ieee80211_vif *vif, generic =3D (struct wtbl_generic *)tlv; =20 if (sta) { + if (vif->type =3D=3D NL80211_IFTYPE_STATION) + generic->partial_aid =3D cpu_to_le16(vif->bss_conf.aid); + else + generic->partial_aid =3D cpu_to_le16(sta->aid); memcpy(generic->peer_addr, sta->addr, ETH_ALEN); - generic->partial_aid =3D cpu_to_le16(sta->aid); generic->muar_idx =3D mvif->omac_idx; generic->qos =3D sta->wme; } else { @@ -1318,12 +1309,15 @@ mt7915_mcu_sta_basic_tlv(struct sk_buff *skb, struc= t ieee80211_vif *vif, case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: basic->conn_type =3D cpu_to_le32(CONNECTION_INFRA_STA); + basic->aid =3D cpu_to_le16(sta->aid); break; case NL80211_IFTYPE_STATION: basic->conn_type =3D cpu_to_le32(CONNECTION_INFRA_AP); + basic->aid =3D cpu_to_le16(vif->bss_conf.aid); break; case NL80211_IFTYPE_ADHOC: basic->conn_type =3D cpu_to_le32(CONNECTION_IBSS_ADHOC); + basic->aid =3D cpu_to_le16(sta->aid); break; default: WARN_ON(1); @@ -1331,7 +1325,6 @@ mt7915_mcu_sta_basic_tlv(struct sk_buff *skb, struct = ieee80211_vif *vif, } =20 memcpy(basic->peer_addr, sta->addr, ETH_ALEN); - basic->aid =3D cpu_to_le16(sta->aid); basic->qos =3D sta->wme; } =20 @@ -1339,11 +1332,9 @@ static void mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, struct ieee80211_vif *vif) { - struct mt7915_sta *msta =3D (struct mt7915_sta *)sta->drv_priv; struct mt7915_vif *mvif =3D (struct mt7915_vif *)vif->drv_priv; struct ieee80211_he_cap_elem *elem =3D &sta->he_cap.he_cap_elem; - enum nl80211_band band =3D msta->vif->phy->mt76->chandef.chan->band; - const u16 *mcs_mask =3D msta->vif->bitrate_mask.control[band].he_mcs; + struct ieee80211_he_mcs_nss_supp mcs_map; struct sta_rec_he *he; struct tlv *tlv; u32 cap =3D 0; @@ -1433,22 +1424,23 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct i= eee80211_sta *sta, =20 he->he_cap =3D cpu_to_le32(cap); =20 + mcs_map =3D sta->he_cap.he_mcs_nss_supp; switch (sta->bandwidth) { case IEEE80211_STA_RX_BW_160: if (elem->phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) mt7915_mcu_set_sta_he_mcs(sta, &he->max_nss_mcs[CMD_HE_MCS_BW8080], - mcs_mask); + le16_to_cpu(mcs_map.rx_mcs_80p80)); =20 mt7915_mcu_set_sta_he_mcs(sta, &he->max_nss_mcs[CMD_HE_MCS_BW160], - mcs_mask); + le16_to_cpu(mcs_map.rx_mcs_160)); fallthrough; default: mt7915_mcu_set_sta_he_mcs(sta, &he->max_nss_mcs[CMD_HE_MCS_BW80], - mcs_mask); + le16_to_cpu(mcs_map.rx_mcs_80)); break; } =20 @@ -1523,9 +1515,6 @@ mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct i= eee80211_sta *sta, vif->type !=3D NL80211_IFTYPE_AP) return; =20 - if (!sta->vht_cap.vht_supported) - return; - tlv =3D mt7915_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru)); =20 muru =3D (struct sta_rec_muru *)tlv; @@ -1533,9 +1522,12 @@ mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct = ieee80211_sta *sta, muru->cfg.mimo_dl_en =3D mvif->cap.he_mu_ebfer || mvif->cap.vht_mu_ebfer || mvif->cap.vht_mu_ebfee; + muru->cfg.mimo_ul_en =3D true; + muru->cfg.ofdma_dl_en =3D true; =20 - muru->mimo_dl.vht_mu_bfee =3D - !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE); + if (sta->vht_cap.vht_supported) + muru->mimo_dl.vht_mu_bfee =3D + !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE); =20 if (!sta->he_cap.has_he) return; @@ -1543,13 +1535,11 @@ mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct= ieee80211_sta *sta, muru->mimo_dl.partial_bw_dl_mimo =3D HE_PHY(CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO, elem->phy_cap_info[6]); =20 - muru->cfg.mimo_ul_en =3D true; muru->mimo_ul.full_ul_mimo =3D HE_PHY(CAP2_UL_MU_FULL_MU_MIMO, elem->phy_cap_info[2]); muru->mimo_ul.partial_ul_mimo =3D HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]); =20 - muru->cfg.ofdma_dl_en =3D true; muru->ofdma_dl.punc_pream_rx =3D HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]); muru->ofdma_dl.he_20m_in_40m_2g =3D @@ -2132,9 +2122,12 @@ mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *de= v, phy.sgi |=3D gi << (i << (_he)); \ phy.he_ltf |=3D mask->control[band].he_ltf << (i << (_he));\ } \ - for (i =3D 0; i < ARRAY_SIZE(mask->control[band]._mcs); i++) \ - nrates +=3D hweight16(mask->control[band]._mcs[i]); \ - phy.mcs =3D ffs(mask->control[band]._mcs[0]) - 1; \ + for (i =3D 0; i < ARRAY_SIZE(mask->control[band]._mcs); i++) { \ + if (!mask->control[band]._mcs[i]) \ + continue; \ + nrates +=3D hweight16(mask->control[band]._mcs[i]); \ + phy.mcs =3D ffs(mask->control[band]._mcs[i]) - 1; \ + } \ } while (0) =20 if (sta->he_cap.has_he) { @@ -2392,8 +2385,10 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struc= t ieee80211_vif *vif, } =20 ret =3D mt7915_mcu_sta_wtbl_tlv(dev, skb, vif, sta); - if (ret) + if (ret) { + dev_kfree_skb(skb); return ret; + } =20 if (sta && sta->ht_cap.ht_supported) { /* starec amsdu */ @@ -2407,8 +2402,10 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struc= t ieee80211_vif *vif, } =20 ret =3D mt7915_mcu_add_group(dev, vif, sta); - if (ret) + if (ret) { + dev_kfree_skb(skb); return ret; + } out: return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(STA_REC_UPDATE), true); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/= net/wireless/mediatek/mt76/mt7921/debugfs.c index 86fd7292b229..196b50e616fe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c @@ -129,23 +129,22 @@ mt7921_queues_acq(struct seq_file *s, void *data) =20 mt7921_mutex_acquire(dev); =20 - for (i =3D 0; i < 16; i++) { - int j, acs =3D i / 4, index =3D i % 4; + for (i =3D 0; i < 4; i++) { u32 ctrl, val, qlen =3D 0; + int j; =20 - val =3D mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, index)); - ctrl =3D BIT(31) | BIT(15) | (acs << 8); + val =3D mt76_rr(dev, MT_PLE_AC_QEMPTY(i)); + ctrl =3D BIT(31) | BIT(11) | (i << 24); =20 for (j =3D 0; j < 32; j++) { if (val & BIT(j)) continue; =20 - mt76_wr(dev, MT_PLE_FL_Q0_CTRL, - ctrl | (j + (index << 5))); + mt76_wr(dev, MT_PLE_FL_Q0_CTRL, ctrl | j); qlen +=3D mt76_get_field(dev, MT_PLE_FL_Q3_CTRL, GENMASK(11, 0)); } - seq_printf(s, "AC%d%d: queued=3D%d\n", acs, index, qlen); + seq_printf(s, "AC%d: queued=3D%d\n", i, qlen); } =20 mt7921_mutex_release(dev); @@ -291,13 +290,12 @@ mt7921_pm_set(void *data, u64 val) pm->enable =3D false; mt76_connac_pm_wake(&dev->mphy, pm); =20 + pm->enable =3D val; ieee80211_iterate_active_interfaces(mt76_hw(dev), IEEE80211_IFACE_ITER_RESUME_ALL, mt7921_pm_interface_iter, dev); =20 mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable); - - pm->enable =3D val; mt76_connac_power_save_sched(&dev->mphy, pm); out: mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/= wireless/mediatek/mt76/mt7921/dma.c index cdff1fd52d93..39d6ce4ecddd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c @@ -78,110 +78,6 @@ static void mt7921_dma_prefetch(struct mt7921_dev *dev) mt76_wr(dev, MT_WFDMA0_TX_RING17_EXT_CTRL, PREFETCH(0x380, 0x4)); } =20 -static u32 __mt7921_reg_addr(struct mt7921_dev *dev, u32 addr) -{ - static const struct { - u32 phys; - u32 mapped; - u32 size; - } fixed_map[] =3D { - { 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */ - { 0x820ed000, 0x24800, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */ - { 0x820e4000, 0x21000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */ - { 0x820e7000, 0x21e00, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */ - { 0x820eb000, 0x24200, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */ - { 0x820e2000, 0x20800, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */ - { 0x820e3000, 0x20c00, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */ - { 0x820e5000, 0x21400, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */ - { 0x00400000, 0x80000, 0x10000 }, /* WF_MCU_SYSRAM */ - { 0x00410000, 0x90000, 0x10000 }, /* WF_MCU_SYSRAM (configure register) = */ - { 0x40000000, 0x70000, 0x10000 }, /* WF_UMAC_SYSRAM */ - { 0x54000000, 0x02000, 0x1000 }, /* WFDMA PCIE0 MCU DMA0 */ - { 0x55000000, 0x03000, 0x1000 }, /* WFDMA PCIE0 MCU DMA1 */ - { 0x58000000, 0x06000, 0x1000 }, /* WFDMA PCIE1 MCU DMA0 (MEM_DMA) */ - { 0x59000000, 0x07000, 0x1000 }, /* WFDMA PCIE1 MCU DMA1 */ - { 0x7c000000, 0xf0000, 0x10000 }, /* CONN_INFRA */ - { 0x7c020000, 0xd0000, 0x10000 }, /* CONN_INFRA, WFDMA */ - { 0x7c060000, 0xe0000, 0x10000 }, /* CONN_INFRA, conn_host_csr_top */ - { 0x80020000, 0xb0000, 0x10000 }, /* WF_TOP_MISC_OFF */ - { 0x81020000, 0xc0000, 0x10000 }, /* WF_TOP_MISC_ON */ - { 0x820c0000, 0x08000, 0x4000 }, /* WF_UMAC_TOP (PLE) */ - { 0x820c8000, 0x0c000, 0x2000 }, /* WF_UMAC_TOP (PSE) */ - { 0x820cc000, 0x0e000, 0x1000 }, /* WF_UMAC_TOP (PP) */ - { 0x820cd000, 0x0f000, 0x1000 }, /* WF_MDP_TOP */ - { 0x820ce000, 0x21c00, 0x0200 }, /* WF_LMAC_TOP (WF_SEC) */ - { 0x820cf000, 0x22000, 0x1000 }, /* WF_LMAC_TOP (WF_PF) */ - { 0x820e0000, 0x20000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_CFG) */ - { 0x820e1000, 0x20400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_TRB) */ - { 0x820e9000, 0x23400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */ - { 0x820ea000, 0x24000, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_ETBF) */ - { 0x820ec000, 0x24600, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_INT) */ - { 0x820f0000, 0xa0000, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_CFG) */ - { 0x820f1000, 0xa0600, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_TRB) */ - { 0x820f2000, 0xa0800, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_AGG) */ - { 0x820f3000, 0xa0c00, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_ARB) */ - { 0x820f4000, 0xa1000, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_TMAC) */ - { 0x820f5000, 0xa1400, 0x0800 }, /* WF_LMAC_TOP BN1 (WF_RMAC) */ - { 0x820f7000, 0xa1e00, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_DMA) */ - { 0x820f9000, 0xa3400, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_WTBLOFF) */ - { 0x820fa000, 0xa4000, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_ETBF) */ - { 0x820fb000, 0xa4200, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_LPON) */ - { 0x820fc000, 0xa4600, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_INT) */ - { 0x820fd000, 0xa4800, 0x0800 }, /* WF_LMAC_TOP BN1 (WF_MIB) */ - }; - int i; - - if (addr < 0x100000) - return addr; - - for (i =3D 0; i < ARRAY_SIZE(fixed_map); i++) { - u32 ofs; - - if (addr < fixed_map[i].phys) - continue; - - ofs =3D addr - fixed_map[i].phys; - if (ofs > fixed_map[i].size) - continue; - - return fixed_map[i].mapped + ofs; - } - - if ((addr >=3D 0x18000000 && addr < 0x18c00000) || - (addr >=3D 0x70000000 && addr < 0x78000000) || - (addr >=3D 0x7c000000 && addr < 0x7c400000)) - return mt7921_reg_map_l1(dev, addr); - - dev_err(dev->mt76.dev, "Access currently unsupported address %08x\n", - addr); - - return 0; -} - -static u32 mt7921_rr(struct mt76_dev *mdev, u32 offset) -{ - struct mt7921_dev *dev =3D container_of(mdev, struct mt7921_dev, mt76); - u32 addr =3D __mt7921_reg_addr(dev, offset); - - return dev->bus_ops->rr(mdev, addr); -} - -static void mt7921_wr(struct mt76_dev *mdev, u32 offset, u32 val) -{ - struct mt7921_dev *dev =3D container_of(mdev, struct mt7921_dev, mt76); - u32 addr =3D __mt7921_reg_addr(dev, offset); - - dev->bus_ops->wr(mdev, addr, val); -} - -static u32 mt7921_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) -{ - struct mt7921_dev *dev =3D container_of(mdev, struct mt7921_dev, mt76); - u32 addr =3D __mt7921_reg_addr(dev, offset); - - return dev->bus_ops->rmw(mdev, addr, mask, val); -} - static int mt7921_dma_disable(struct mt7921_dev *dev, bool force) { if (force) { @@ -341,23 +237,8 @@ int mt7921_wpdma_reinit_cond(struct mt7921_dev *dev) =20 int mt7921_dma_init(struct mt7921_dev *dev) { - struct mt76_bus_ops *bus_ops; int ret; =20 - dev->phy.dev =3D dev; - dev->phy.mt76 =3D &dev->mt76.phy; - dev->mt76.phy.priv =3D &dev->phy; - dev->bus_ops =3D dev->mt76.bus; - bus_ops =3D devm_kmemdup(dev->mt76.dev, dev->bus_ops, sizeof(*bus_ops), - GFP_KERNEL); - if (!bus_ops) - return -ENOMEM; - - bus_ops->rr =3D mt7921_rr; - bus_ops->wr =3D mt7921_wr; - bus_ops->rmw =3D mt7921_rmw; - dev->mt76.bus =3D bus_ops; - mt76_dma_attach(&dev->mt76); =20 ret =3D mt7921_dma_disable(dev, true); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/= wireless/mediatek/mt76/mt7921/mac.c index fc21a78b37c4..57fd626b40da 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -836,9 +836,15 @@ mt7921_mac_write_txwi_80211(struct mt7921_dev *dev, __= le32 *txwi, txwi[3] |=3D cpu_to_le32(val); } =20 - val =3D FIELD_PREP(MT_TXD7_TYPE, fc_type) | - FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype); - txwi[7] |=3D cpu_to_le32(val); + if (mt76_is_mmio(&dev->mt76)) { + val =3D FIELD_PREP(MT_TXD7_TYPE, fc_type) | + FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype); + txwi[7] |=3D cpu_to_le32(val); + } else { + val =3D FIELD_PREP(MT_TXD8_L_TYPE, fc_type) | + FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype); + txwi[8] |=3D cpu_to_le32(val); + } } =20 void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, @@ -1014,7 +1020,6 @@ mt7921_mac_add_txs_skb(struct mt7921_dev *dev, struct= mt76_wcid *wcid, int pid, break; case MT_PHY_TYPE_HT: case MT_PHY_TYPE_HT_GF: - rate.mcs +=3D (rate.nss - 1) * 8; if (rate.mcs > 31) goto out; =20 @@ -1472,6 +1477,14 @@ void mt7921_pm_power_save_work(struct work_struct *w= ork) test_bit(MT76_HW_SCHED_SCANNING, &mphy->state)) goto out; =20 + if (mutex_is_locked(&dev->mt76.mutex)) + /* if mt76 mutex is held we should not put the device + * to sleep since we are currently accessing device + * register map. We need to wait for the next power_save + * trigger. + */ + goto out; + if (time_is_after_jiffies(dev->pm.last_activity + delta)) { delta =3D dev->pm.last_activity + delta - jiffies; goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/= wireless/mediatek/mt76/mt7921/mac.h index 544a1c33126a..12e1cf8abe6e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h @@ -284,6 +284,9 @@ enum tx_mcu_port_q_idx { #define MT_TXD7_HW_AMSDU BIT(10) #define MT_TXD7_TX_TIME GENMASK(9, 0) =20 +#define MT_TXD8_L_TYPE GENMASK(5, 4) +#define MT_TXD8_L_SUB_TYPE GENMASK(3, 0) + #define MT_TX_RATE_STBC BIT(13) #define MT_TX_RATE_NSS GENMASK(12, 10) #define MT_TX_RATE_MODE GENMASK(9, 6) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/= wireless/mediatek/mt76/mt7921/mcu.c index 4c6adbb96955..50c953b08ed0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -912,33 +912,28 @@ EXPORT_SYMBOL_GPL(mt7921_mcu_exit); =20 int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif) { -#define WMM_AIFS_SET BIT(0) -#define WMM_CW_MIN_SET BIT(1) -#define WMM_CW_MAX_SET BIT(2) -#define WMM_TXOP_SET BIT(3) -#define WMM_PARAM_SET GENMASK(3, 0) -#define TX_CMD_MODE 1 + struct mt7921_vif *mvif =3D (struct mt7921_vif *)vif->drv_priv; + struct edca { - u8 queue; - u8 set; - u8 aifs; - u8 cw_min; + __le16 cw_min; __le16 cw_max; __le16 txop; - }; + __le16 aifs; + u8 guardtime; + u8 acm; + } __packed; struct mt7921_mcu_tx { - u8 total; - u8 action; - u8 valid; - u8 mode; - struct edca edca[IEEE80211_NUM_ACS]; + u8 bss_idx; + u8 qos; + u8 wmm_idx; + u8 pad; } __packed req =3D { - .valid =3D true, - .mode =3D TX_CMD_MODE, - .total =3D IEEE80211_NUM_ACS, + .bss_idx =3D mvif->mt76.idx, + .qos =3D vif->bss_conf.qos, + .wmm_idx =3D mvif->mt76.wmm_idx, }; - struct mt7921_vif *mvif =3D (struct mt7921_vif *)vif->drv_priv; + struct mu_edca { u8 cw_min; u8 cw_max; @@ -962,30 +957,29 @@ int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct = ieee80211_vif *vif) .qos =3D vif->bss_conf.qos, .wmm_idx =3D mvif->mt76.wmm_idx, }; + int to_aci[] =3D {1, 0, 2, 3}; int ac, ret; =20 for (ac =3D 0; ac < IEEE80211_NUM_ACS; ac++) { struct ieee80211_tx_queue_params *q =3D &mvif->queue_params[ac]; - struct edca *e =3D &req.edca[ac]; + struct edca *e =3D &req.edca[to_aci[ac]]; =20 - e->set =3D WMM_PARAM_SET; - e->queue =3D ac + mvif->mt76.wmm_idx * MT7921_MAX_WMM_SETS; e->aifs =3D q->aifs; e->txop =3D cpu_to_le16(q->txop); =20 if (q->cw_min) - e->cw_min =3D fls(q->cw_min); + e->cw_min =3D cpu_to_le16(q->cw_min); else e->cw_min =3D 5; =20 if (q->cw_max) - e->cw_max =3D cpu_to_le16(fls(q->cw_max)); + e->cw_max =3D cpu_to_le16(q->cw_max); else e->cw_max =3D cpu_to_le16(10); } =20 - ret =3D mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EDCA_UPDATE), - &req, sizeof(req), true); + ret =3D mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_EDCA_PARMS), &req, + sizeof(req), false); if (ret) return ret; =20 @@ -995,7 +989,6 @@ int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ie= ee80211_vif *vif) for (ac =3D 0; ac < IEEE80211_NUM_ACS; ac++) { struct ieee80211_he_mu_edca_param_ac_rec *q; struct mu_edca *e; - int to_aci[] =3D {1, 0, 2, 3}; =20 if (!mvif->queue_params[ac].mu_edca) break; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/n= et/wireless/mediatek/mt76/mt7921/mt7921.h index 96647801850a..33f8e5b541b3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -452,6 +452,7 @@ int mt7921e_mcu_init(struct mt7921_dev *dev); int mt7921s_wfsys_reset(struct mt7921_dev *dev); int mt7921s_mac_reset(struct mt7921_dev *dev); int mt7921s_init_reset(struct mt7921_dev *dev); +int __mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev); int mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev); int mt7921e_mcu_fw_pmctrl(struct mt7921_dev *dev); =20 diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/= wireless/mediatek/mt76/mt7921/pci.c index 40186e6cd865..006e6a11e6fa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -119,6 +119,110 @@ static void mt7921e_unregister_device(struct mt7921_d= ev *dev) mt76_free_device(&dev->mt76); } =20 +static u32 __mt7921_reg_addr(struct mt7921_dev *dev, u32 addr) +{ + static const struct { + u32 phys; + u32 mapped; + u32 size; + } fixed_map[] =3D { + { 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */ + { 0x820ed000, 0x24800, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */ + { 0x820e4000, 0x21000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */ + { 0x820e7000, 0x21e00, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */ + { 0x820eb000, 0x24200, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */ + { 0x820e2000, 0x20800, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */ + { 0x820e3000, 0x20c00, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */ + { 0x820e5000, 0x21400, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */ + { 0x00400000, 0x80000, 0x10000 }, /* WF_MCU_SYSRAM */ + { 0x00410000, 0x90000, 0x10000 }, /* WF_MCU_SYSRAM (configure register) = */ + { 0x40000000, 0x70000, 0x10000 }, /* WF_UMAC_SYSRAM */ + { 0x54000000, 0x02000, 0x1000 }, /* WFDMA PCIE0 MCU DMA0 */ + { 0x55000000, 0x03000, 0x1000 }, /* WFDMA PCIE0 MCU DMA1 */ + { 0x58000000, 0x06000, 0x1000 }, /* WFDMA PCIE1 MCU DMA0 (MEM_DMA) */ + { 0x59000000, 0x07000, 0x1000 }, /* WFDMA PCIE1 MCU DMA1 */ + { 0x7c000000, 0xf0000, 0x10000 }, /* CONN_INFRA */ + { 0x7c020000, 0xd0000, 0x10000 }, /* CONN_INFRA, WFDMA */ + { 0x7c060000, 0xe0000, 0x10000 }, /* CONN_INFRA, conn_host_csr_top */ + { 0x80020000, 0xb0000, 0x10000 }, /* WF_TOP_MISC_OFF */ + { 0x81020000, 0xc0000, 0x10000 }, /* WF_TOP_MISC_ON */ + { 0x820c0000, 0x08000, 0x4000 }, /* WF_UMAC_TOP (PLE) */ + { 0x820c8000, 0x0c000, 0x2000 }, /* WF_UMAC_TOP (PSE) */ + { 0x820cc000, 0x0e000, 0x1000 }, /* WF_UMAC_TOP (PP) */ + { 0x820cd000, 0x0f000, 0x1000 }, /* WF_MDP_TOP */ + { 0x820ce000, 0x21c00, 0x0200 }, /* WF_LMAC_TOP (WF_SEC) */ + { 0x820cf000, 0x22000, 0x1000 }, /* WF_LMAC_TOP (WF_PF) */ + { 0x820e0000, 0x20000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_CFG) */ + { 0x820e1000, 0x20400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_TRB) */ + { 0x820e9000, 0x23400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */ + { 0x820ea000, 0x24000, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_ETBF) */ + { 0x820ec000, 0x24600, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_INT) */ + { 0x820f0000, 0xa0000, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_CFG) */ + { 0x820f1000, 0xa0600, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_TRB) */ + { 0x820f2000, 0xa0800, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_AGG) */ + { 0x820f3000, 0xa0c00, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_ARB) */ + { 0x820f4000, 0xa1000, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_TMAC) */ + { 0x820f5000, 0xa1400, 0x0800 }, /* WF_LMAC_TOP BN1 (WF_RMAC) */ + { 0x820f7000, 0xa1e00, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_DMA) */ + { 0x820f9000, 0xa3400, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_WTBLOFF) */ + { 0x820fa000, 0xa4000, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_ETBF) */ + { 0x820fb000, 0xa4200, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_LPON) */ + { 0x820fc000, 0xa4600, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_INT) */ + { 0x820fd000, 0xa4800, 0x0800 }, /* WF_LMAC_TOP BN1 (WF_MIB) */ + }; + int i; + + if (addr < 0x100000) + return addr; + + for (i =3D 0; i < ARRAY_SIZE(fixed_map); i++) { + u32 ofs; + + if (addr < fixed_map[i].phys) + continue; + + ofs =3D addr - fixed_map[i].phys; + if (ofs > fixed_map[i].size) + continue; + + return fixed_map[i].mapped + ofs; + } + + if ((addr >=3D 0x18000000 && addr < 0x18c00000) || + (addr >=3D 0x70000000 && addr < 0x78000000) || + (addr >=3D 0x7c000000 && addr < 0x7c400000)) + return mt7921_reg_map_l1(dev, addr); + + dev_err(dev->mt76.dev, "Access currently unsupported address %08x\n", + addr); + + return 0; +} + +static u32 mt7921_rr(struct mt76_dev *mdev, u32 offset) +{ + struct mt7921_dev *dev =3D container_of(mdev, struct mt7921_dev, mt76); + u32 addr =3D __mt7921_reg_addr(dev, offset); + + return dev->bus_ops->rr(mdev, addr); +} + +static void mt7921_wr(struct mt76_dev *mdev, u32 offset, u32 val) +{ + struct mt7921_dev *dev =3D container_of(mdev, struct mt7921_dev, mt76); + u32 addr =3D __mt7921_reg_addr(dev, offset); + + dev->bus_ops->wr(mdev, addr, val); +} + +static u32 mt7921_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) +{ + struct mt7921_dev *dev =3D container_of(mdev, struct mt7921_dev, mt76); + u32 addr =3D __mt7921_reg_addr(dev, offset); + + return dev->bus_ops->rmw(mdev, addr, mask, val); +} + static int mt7921_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -149,6 +253,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev, .fw_own =3D mt7921e_mcu_fw_pmctrl, }; =20 + struct mt76_bus_ops *bus_ops; struct mt7921_dev *dev; struct mt76_dev *mdev; int ret; @@ -186,6 +291,25 @@ static int mt7921_pci_probe(struct pci_dev *pdev, =20 mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); tasklet_init(&dev->irq_tasklet, mt7921_irq_tasklet, (unsigned long)dev); + + dev->phy.dev =3D dev; + dev->phy.mt76 =3D &dev->mt76.phy; + dev->mt76.phy.priv =3D &dev->phy; + dev->bus_ops =3D dev->mt76.bus; + bus_ops =3D devm_kmemdup(dev->mt76.dev, dev->bus_ops, sizeof(*bus_ops), + GFP_KERNEL); + if (!bus_ops) + return -ENOMEM; + + bus_ops->rr =3D mt7921_rr; + bus_ops->wr =3D mt7921_wr; + bus_ops->rmw =3D mt7921_rmw; + dev->mt76.bus =3D bus_ops; + + ret =3D __mt7921e_mcu_drv_pmctrl(dev); + if (ret) + return ret; + mdev->rev =3D (mt7921_l1_rr(dev, MT_HW_CHIPID) << 16) | (mt7921_l1_rr(dev, MT_HW_REV) & 0xff); dev_err(mdev->dev, "ASIC revision: %04x\n", mdev->rev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c b/drivers/= net/wireless/mediatek/mt76/mt7921/pci_mcu.c index 7b34c7f2ab3a..3f80beca965a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c @@ -59,10 +59,8 @@ int mt7921e_mcu_init(struct mt7921_dev *dev) return err; } =20 -int mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev) +int __mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev) { - struct mt76_phy *mphy =3D &dev->mt76.phy; - struct mt76_connac_pm *pm =3D &dev->pm; int i, err =3D 0; =20 for (i =3D 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) { @@ -75,9 +73,21 @@ int mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev) if (i =3D=3D MT7921_DRV_OWN_RETRY_COUNT) { dev_err(dev->mt76.dev, "driver own failed\n"); err =3D -EIO; - goto out; } =20 + return err; +} + +int mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev) +{ + struct mt76_phy *mphy =3D &dev->mt76.phy; + struct mt76_connac_pm *pm =3D &dev->pm; + int err; + + err =3D __mt7921e_mcu_drv_pmctrl(dev); + if (err < 0) + goto out; + mt7921_wpdma_reinit_cond(dev); clear_bit(MT76_STATE_PM, &mphy->state); =20 diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h b/drivers/net= /wireless/mediatek/mt76/mt7921/regs.h index cbd38122c510..c8c92faa4624 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h @@ -17,13 +17,12 @@ #define MT_PLE_BASE 0x820c0000 #define MT_PLE(ofs) (MT_PLE_BASE + (ofs)) =20 -#define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0) -#define MT_PLE_FL_Q1_CTRL MT_PLE(0x1b4) -#define MT_PLE_FL_Q2_CTRL MT_PLE(0x1b8) -#define MT_PLE_FL_Q3_CTRL MT_PLE(0x1bc) +#define MT_PLE_FL_Q0_CTRL MT_PLE(0x3e0) +#define MT_PLE_FL_Q1_CTRL MT_PLE(0x3e4) +#define MT_PLE_FL_Q2_CTRL MT_PLE(0x3e8) +#define MT_PLE_FL_Q3_CTRL MT_PLE(0x3ec) =20 -#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x300 + 0x10 * (ac) + \ - ((n) << 2)) +#define MT_PLE_AC_QEMPTY(_n) MT_PLE(0x500 + 0x40 * (_n)) #define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2)) =20 #define MT_MDP_BASE 0x820cd000 diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c b/drivers= /net/wireless/mediatek/mt76/mt7921/sdio_mcu.c index 437cddad9a90..353d99fef065 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c @@ -49,6 +49,26 @@ mt7921s_mcu_send_message(struct mt76_dev *mdev, struct s= k_buff *skb, return ret; } =20 +static u32 mt7921s_read_rm3r(struct mt7921_dev *dev) +{ + struct mt76_sdio *sdio =3D &dev->mt76.sdio; + + return sdio_readl(sdio->func, MCR_D2HRM3R, NULL); +} + +static u32 mt7921s_clear_rm3r_drv_own(struct mt7921_dev *dev) +{ + struct mt76_sdio *sdio =3D &dev->mt76.sdio; + u32 val; + + val =3D sdio_readl(sdio->func, MCR_D2HRM3R, NULL); + if (val) + sdio_writel(sdio->func, H2D_SW_INT_CLEAR_MAILBOX_ACK, + MCR_WSICR, NULL); + + return val; +} + int mt7921s_mcu_init(struct mt7921_dev *dev) { static const struct mt76_mcu_ops mt7921s_mcu_ops =3D { @@ -88,6 +108,12 @@ int mt7921s_mcu_drv_pmctrl(struct mt7921_dev *dev) =20 err =3D readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status, status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000); + + if (!err && test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) + err =3D readx_poll_timeout(mt7921s_read_rm3r, dev, status, + status & D2HRM3R_IS_DRIVER_OWN, + 2000, 1000000); + sdio_release_host(func); =20 if (err < 0) { @@ -115,12 +141,24 @@ int mt7921s_mcu_fw_pmctrl(struct mt7921_dev *dev) =20 sdio_claim_host(func); =20 + if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) { + err =3D readx_poll_timeout(mt7921s_clear_rm3r_drv_own, + dev, status, + !(status & D2HRM3R_IS_DRIVER_OWN), + 2000, 1000000); + if (err < 0) { + dev_err(dev->mt76.dev, "mailbox ACK not cleared\n"); + goto err; + } + } + sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, NULL); =20 err =3D readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status, !(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000); sdio_release_host(func); =20 +err: if (err < 0) { dev_err(dev->mt76.dev, "firmware own failed\n"); clear_bit(MT76_STATE_PM, &mphy->state); diff --git a/drivers/net/wireless/mediatek/mt76/sdio.h b/drivers/net/wirele= ss/mediatek/mt76/sdio.h index 99db4ad93b7c..27d5d2077eba 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio.h +++ b/drivers/net/wireless/mediatek/mt76/sdio.h @@ -65,6 +65,7 @@ #define MCR_H2DSM0R 0x0070 #define H2D_SW_INT_READ BIT(16) #define H2D_SW_INT_WRITE BIT(17) +#define H2D_SW_INT_CLEAR_MAILBOX_ACK BIT(22) =20 #define MCR_H2DSM1R 0x0074 #define MCR_D2HRM0R 0x0078 @@ -109,6 +110,7 @@ #define MCR_H2DSM2R 0x0160 /* supported in CONNAC2 */ #define MCR_H2DSM3R 0x0164 /* supported in CONNAC2 */ #define MCR_D2HRM3R 0x0174 /* supported in CONNAC2 */ +#define D2HRM3R_IS_DRIVER_OWN BIT(0) #define MCR_WTQCR8 0x0190 /* supported in CONNAC2 */ #define MCR_WTQCR9 0x0194 /* supported in CONNAC2 */ #define MCR_WTQCR10 0x0198 /* supported in CONNAC2 */ diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index e3a3dc3e45b4..03f0953440b5 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -382,6 +382,8 @@ static int ray_config(struct pcmcia_device *link) goto failed; local->sram =3D ioremap(link->resource[2]->start, resource_size(link->resource[2])); + if (!local->sram) + goto failed; =20 /*** Set up 16k window for shared memory (receive buffer) ***************/ link->resource[3]->flags |=3D @@ -396,6 +398,8 @@ static int ray_config(struct pcmcia_device *link) goto failed; local->rmem =3D ioremap(link->resource[3]->start, resource_size(link->resource[3])); + if (!local->rmem) + goto failed; =20 /*** Set up window for attribute memory **********************************= */ link->resource[4]->flags |=3D @@ -410,6 +414,8 @@ static int ray_config(struct pcmcia_device *link) goto failed; local->amem =3D ioremap(link->resource[4]->start, resource_size(link->resource[4])); + if (!local->amem) + goto failed; =20 dev_dbg(&link->dev, "ray_config sram=3D%p\n", local->sram); dev_dbg(&link->dev, "ray_config rmem=3D%p\n", local->rmem); diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index 9ccf3d608799..70ad891a76ba 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -1025,6 +1025,9 @@ static unsigned long default_align(struct nd_region *= nd_region) } } =20 + if (nd_region->ndr_size < MEMREMAP_COMPAT_ALIGN_MAX) + align =3D PAGE_SIZE; + mappings =3D max_t(u16, 1, nd_region->ndr_mappings); div_u64_rem(align, mappings, &remainder); if (remainder) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 5785f6abf194..ecb98d1ad9f6 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1685,13 +1685,6 @@ static void nvme_config_discard(struct gendisk *disk= , struct nvme_ns *ns) blk_queue_max_write_zeroes_sectors(queue, UINT_MAX); } =20 -static bool nvme_ns_ids_valid(struct nvme_ns_ids *ids) -{ - return !uuid_is_null(&ids->uuid) || - memchr_inv(ids->nguid, 0, sizeof(ids->nguid)) || - memchr_inv(ids->eui64, 0, sizeof(ids->eui64)); -} - static bool nvme_ns_ids_equal(struct nvme_ns_ids *a, struct nvme_ns_ids *b) { return uuid_equal(&a->uuid, &b->uuid) && @@ -1867,9 +1860,6 @@ static void nvme_update_disk_info(struct gendisk *dis= k, nvme_config_discard(disk, ns); blk_queue_max_write_zeroes_sectors(disk->queue, ns->ctrl->max_zeroes_sectors); - - set_disk_ro(disk, (id->nsattr & NVME_NS_ATTR_RO) || - test_bit(NVME_NS_FORCE_RO, &ns->flags)); } =20 static inline bool nvme_first_scan(struct gendisk *disk) @@ -1930,6 +1920,8 @@ static int nvme_update_ns_info(struct nvme_ns *ns, st= ruct nvme_id_ns *id) goto out_unfreeze; } =20 + set_disk_ro(ns->disk, (id->nsattr & NVME_NS_ATTR_RO) || + test_bit(NVME_NS_FORCE_RO, &ns->flags)); set_bit(NVME_NS_READY, &ns->flags); blk_mq_unfreeze_queue(ns->disk->queue); =20 @@ -1942,6 +1934,9 @@ static int nvme_update_ns_info(struct nvme_ns *ns, st= ruct nvme_id_ns *id) if (nvme_ns_head_multipath(ns->head)) { blk_mq_freeze_queue(ns->head->disk->queue); nvme_update_disk_info(ns->head->disk, ns, id); + set_disk_ro(ns->head->disk, + (id->nsattr & NVME_NS_ATTR_RO) || + test_bit(NVME_NS_FORCE_RO, &ns->flags)); nvme_mpath_revalidate_paths(ns); blk_stack_limits(&ns->head->disk->queue->limits, &ns->queue->limits, 0); @@ -3588,15 +3583,20 @@ static const struct attribute_group *nvme_dev_attr_= groups[] =3D { NULL, }; =20 -static struct nvme_ns_head *nvme_find_ns_head(struct nvme_subsystem *subsy= s, +static struct nvme_ns_head *nvme_find_ns_head(struct nvme_ctrl *ctrl, unsigned nsid) { struct nvme_ns_head *h; =20 - lockdep_assert_held(&subsys->lock); + lockdep_assert_held(&ctrl->subsys->lock); =20 - list_for_each_entry(h, &subsys->nsheads, entry) { - if (h->ns_id !=3D nsid) + list_for_each_entry(h, &ctrl->subsys->nsheads, entry) { + /* + * Private namespaces can share NSIDs under some conditions. + * In that case we can't use the same ns_head for namespaces + * with the same NSID. + */ + if (h->ns_id !=3D nsid || !nvme_is_unique_nsid(ctrl, h)) continue; if (!list_empty(&h->list) && nvme_tryget_ns_head(h)) return h; @@ -3605,16 +3605,24 @@ static struct nvme_ns_head *nvme_find_ns_head(struc= t nvme_subsystem *subsys, return NULL; } =20 -static int __nvme_check_ids(struct nvme_subsystem *subsys, - struct nvme_ns_head *new) +static int nvme_subsys_check_duplicate_ids(struct nvme_subsystem *subsys, + struct nvme_ns_ids *ids) { + bool has_uuid =3D !uuid_is_null(&ids->uuid); + bool has_nguid =3D memchr_inv(ids->nguid, 0, sizeof(ids->nguid)); + bool has_eui64 =3D memchr_inv(ids->eui64, 0, sizeof(ids->eui64)); struct nvme_ns_head *h; =20 lockdep_assert_held(&subsys->lock); =20 list_for_each_entry(h, &subsys->nsheads, entry) { - if (nvme_ns_ids_valid(&new->ids) && - nvme_ns_ids_equal(&new->ids, &h->ids)) + if (has_uuid && uuid_equal(&ids->uuid, &h->ids.uuid)) + return -EINVAL; + if (has_nguid && + memcmp(&ids->nguid, &h->ids.nguid, sizeof(ids->nguid)) =3D=3D 0) + return -EINVAL; + if (has_eui64 && + memcmp(&ids->eui64, &h->ids.eui64, sizeof(ids->eui64)) =3D=3D 0) return -EINVAL; } =20 @@ -3713,7 +3721,7 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct= nvme_ctrl *ctrl, head->ids =3D *ids; kref_init(&head->ref); =20 - ret =3D __nvme_check_ids(ctrl->subsys, head); + ret =3D nvme_subsys_check_duplicate_ids(ctrl->subsys, &head->ids); if (ret) { dev_err(ctrl->device, "duplicate IDs for nsid %d\n", nsid); @@ -3756,7 +3764,7 @@ static int nvme_init_ns_head(struct nvme_ns *ns, unsi= gned nsid, int ret =3D 0; =20 mutex_lock(&ctrl->subsys->lock); - head =3D nvme_find_ns_head(ctrl->subsys, nsid); + head =3D nvme_find_ns_head(ctrl, nsid); if (!head) { head =3D nvme_alloc_ns_head(ctrl, nsid, ids); if (IS_ERR(head)) { diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c index 99c2307b04e2..65fe28895ef3 100644 --- a/drivers/nvme/host/multipath.c +++ b/drivers/nvme/host/multipath.c @@ -468,10 +468,11 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, str= uct nvme_ns_head *head) =20 /* * Add a multipath node if the subsystems supports multiple controllers. - * We also do this for private namespaces as the namespace sharing data c= ould - * change after a rescan. + * We also do this for private namespaces as the namespace sharing flag + * could change after a rescan. */ - if (!(ctrl->subsys->cmic & NVME_CTRL_CMIC_MULTI_CTRL) || !multipath) + if (!(ctrl->subsys->cmic & NVME_CTRL_CMIC_MULTI_CTRL) || + !nvme_is_unique_nsid(ctrl, head) || !multipath) return 0; =20 head->disk =3D blk_alloc_disk(ctrl->numa_node); diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 9b095ee01364..ec5d3d4dc2cc 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -712,6 +712,25 @@ static inline bool nvme_check_ready(struct nvme_ctrl *= ctrl, struct request *rq, return queue_live; return __nvme_check_ready(ctrl, rq, queue_live); } + +/* + * NSID shall be unique for all shared namespaces, or if at least one of t= he + * following conditions is met: + * 1. Namespace Management is supported by the controller + * 2. ANA is supported by the controller + * 3. NVM Set are supported by the controller + * + * In other case, private namespace are not required to report a unique NS= ID. + */ +static inline bool nvme_is_unique_nsid(struct nvme_ctrl *ctrl, + struct nvme_ns_head *head) +{ + return head->shared || + (ctrl->oacs & NVME_CTRL_OACS_NS_MNGT_SUPP) || + (ctrl->subsys->cmic & NVME_CTRL_CMIC_ANA) || + (ctrl->ctratt & NVME_CTRL_CTRATT_NVM_SETS); +} + int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd, void *buf, unsigned bufflen); int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *c= md, diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 65e00c64a588..d66e2de044e0 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -30,6 +30,44 @@ static int so_priority; module_param(so_priority, int, 0644); MODULE_PARM_DESC(so_priority, "nvme tcp socket optimize priority"); =20 +#ifdef CONFIG_DEBUG_LOCK_ALLOC +/* lockdep can detect a circular dependency of the form + * sk_lock -> mmap_lock (page fault) -> fs locks -> sk_lock + * because dependencies are tracked for both nvme-tcp and user contexts. U= sing + * a separate class prevents lockdep from conflating nvme-tcp socket use w= ith + * user-space socket API use. + */ +static struct lock_class_key nvme_tcp_sk_key[2]; +static struct lock_class_key nvme_tcp_slock_key[2]; + +static void nvme_tcp_reclassify_socket(struct socket *sock) +{ + struct sock *sk =3D sock->sk; + + if (WARN_ON_ONCE(!sock_allow_reclassification(sk))) + return; + + switch (sk->sk_family) { + case AF_INET: + sock_lock_init_class_and_name(sk, "slock-AF_INET-NVME", + &nvme_tcp_slock_key[0], + "sk_lock-AF_INET-NVME", + &nvme_tcp_sk_key[0]); + break; + case AF_INET6: + sock_lock_init_class_and_name(sk, "slock-AF_INET6-NVME", + &nvme_tcp_slock_key[1], + "sk_lock-AF_INET6-NVME", + &nvme_tcp_sk_key[1]); + break; + default: + WARN_ON_ONCE(1); + } +} +#else +static void nvme_tcp_reclassify_socket(struct socket *sock) { } +#endif + enum nvme_tcp_send_state { NVME_TCP_SEND_CMD_PDU =3D 0, NVME_TCP_SEND_H2C_PDU, @@ -1469,6 +1507,8 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nct= rl, goto err_destroy_mutex; } =20 + nvme_tcp_reclassify_socket(queue->sock); + /* Single syn retry */ tcp_sock_set_syncnt(queue->sock->sk, 1); =20 diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 46935695cfb9..8d0d1f61c650 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -160,9 +160,12 @@ int pci_generic_config_write32(struct pci_bus *bus, un= signed int devfn, * write happen to have any RW1C (write-one-to-clear) bits set, we * just inadvertently cleared something we shouldn't have. */ - dev_warn_ratelimited(&bus->dev, "%d-byte config write to %04x:%02x:%02x.%= d offset %#x may corrupt adjacent RW1C bits\n", - size, pci_domain_nr(bus), bus->number, - PCI_SLOT(devfn), PCI_FUNC(devfn), where); + if (!bus->unsafe_warn) { + dev_warn(&bus->dev, "%d-byte config write to %04x:%02x:%02x.%d offset %#= x may corrupt adjacent RW1C bits\n", + size, pci_domain_nr(bus), bus->number, + PCI_SLOT(devfn), PCI_FUNC(devfn), where); + bus->unsafe_warn =3D 1; + } =20 mask =3D ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8)); tmp =3D readl(addr) & mask; diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller= /dwc/pci-imx6.c index 26f49f797b0f..bbc3a46549f8 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -779,9 +779,7 @@ static int imx6_pcie_start_link(struct dw_pcie *pci) /* Start LTSSM. */ imx6_pcie_ltssm_enable(dev); =20 - ret =3D dw_pcie_wait_for_link(pci); - if (ret) - goto err_reset_phy; + dw_pcie_wait_for_link(pci); =20 if (pci->link_gen =3D=3D 2) { /* Allow Gen2 mode after the link is up. */ @@ -817,11 +815,7 @@ static int imx6_pcie_start_link(struct dw_pcie *pci) } =20 /* Make sure link training is finished as well! */ - ret =3D dw_pcie_wait_for_link(pci); - if (ret) { - dev_err(dev, "Failed to bring link up!\n"); - goto err_reset_phy; - } + dw_pcie_wait_for_link(pci); } else { dev_info(dev, "Link: Gen2 disabled\n"); } diff --git a/drivers/pci/controller/dwc/pcie-fu740.c b/drivers/pci/controll= er/dwc/pcie-fu740.c index 00cde9a248b5..78d002be4f82 100644 --- a/drivers/pci/controller/dwc/pcie-fu740.c +++ b/drivers/pci/controller/dwc/pcie-fu740.c @@ -181,10 +181,59 @@ static int fu740_pcie_start_link(struct dw_pcie *pci) { struct device *dev =3D pci->dev; struct fu740_pcie *afp =3D dev_get_drvdata(dev); + u8 cap_exp =3D dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + int ret; + u32 orig, tmp; + + /* + * Force 2.5GT/s when starting the link, due to some devices not + * probing at higher speeds. This happens with the PCIe switch + * on the Unmatched board when U-Boot has not initialised the PCIe. + * The fix in U-Boot is to force 2.5GT/s, which then gets cleared + * by the soft reset done by this driver. + */ + dev_dbg(dev, "cap_exp at %x\n", cap_exp); + dw_pcie_dbi_ro_wr_en(pci); + + tmp =3D dw_pcie_readl_dbi(pci, cap_exp + PCI_EXP_LNKCAP); + orig =3D tmp & PCI_EXP_LNKCAP_SLS; + tmp &=3D ~PCI_EXP_LNKCAP_SLS; + tmp |=3D PCI_EXP_LNKCAP_SLS_2_5GB; + dw_pcie_writel_dbi(pci, cap_exp + PCI_EXP_LNKCAP, tmp); =20 /* Enable LTSSM */ writel_relaxed(0x1, afp->mgmt_base + PCIEX8MGMT_APP_LTSSM_ENABLE); - return 0; + + ret =3D dw_pcie_wait_for_link(pci); + if (ret) { + dev_err(dev, "error: link did not start\n"); + goto err; + } + + tmp =3D dw_pcie_readl_dbi(pci, cap_exp + PCI_EXP_LNKCAP); + if ((tmp & PCI_EXP_LNKCAP_SLS) !=3D orig) { + dev_dbg(dev, "changing speed back to original\n"); + + tmp &=3D ~PCI_EXP_LNKCAP_SLS; + tmp |=3D orig; + dw_pcie_writel_dbi(pci, cap_exp + PCI_EXP_LNKCAP, tmp); + + tmp =3D dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); + tmp |=3D PORT_LOGIC_SPEED_CHANGE; + dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp); + + ret =3D dw_pcie_wait_for_link(pci); + if (ret) { + dev_err(dev, "error: link did not start at new speed\n"); + goto err; + } + } + + ret =3D 0; +err: + WARN_ON(ret); /* we assume that errors will be very rare */ + dw_pcie_dbi_ro_wr_dis(pci); + return ret; } =20 static int fu740_pcie_host_init(struct pcie_port *pp) diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller= /pci-aardvark.c index b2217e2b3efd..a924564fdbbc 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -844,7 +844,9 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_e= mul *bridge, case PCI_EXP_RTSTA: { u32 isr0 =3D advk_readl(pcie, PCIE_ISR0_REG); u32 msglog =3D advk_readl(pcie, PCIE_MSG_LOG_REG); - *value =3D (isr0 & PCIE_MSG_PM_PME_MASK) << 16 | (msglog >> 16); + *value =3D msglog >> 16; + if (isr0 & PCIE_MSG_PM_PME_MASK) + *value |=3D PCI_EXP_RTSTA_PME; return PCI_BRIDGE_EMUL_HANDLED; } =20 @@ -1381,7 +1383,6 @@ static void advk_pcie_remove_irq_domain(struct advk_p= cie *pcie) static void advk_pcie_handle_msi(struct advk_pcie *pcie) { u32 msi_val, msi_mask, msi_status, msi_idx; - u16 msi_data; =20 msi_mask =3D advk_readl(pcie, PCIE_MSI_MASK_REG); msi_val =3D advk_readl(pcie, PCIE_MSI_STATUS_REG); @@ -1391,13 +1392,9 @@ static void advk_pcie_handle_msi(struct advk_pcie *p= cie) if (!(BIT(msi_idx) & msi_status)) continue; =20 - /* - * msi_idx contains bits [4:0] of the msi_data and msi_data - * contains 16bit MSI interrupt number - */ advk_writel(pcie, BIT(msi_idx), PCIE_MSI_STATUS_REG); - msi_data =3D advk_readl(pcie, PCIE_MSI_PAYLOAD_REG) & PCIE_MSI_DATA_MASK; - generic_handle_irq(msi_data); + if (generic_handle_domain_irq(pcie->msi_inner_domain, msi_idx) =3D=3D -E= INVAL) + dev_err_ratelimited(&pcie->pdev->dev, "unexpected MSI 0x%02x\n", msi_id= x); } =20 advk_writel(pcie, PCIE_ISR0_MSI_INT_PENDING, diff --git a/drivers/pci/controller/pci-xgene.c b/drivers/pci/controller/pc= i-xgene.c index d83dbd977418..02869d3ed031 100644 --- a/drivers/pci/controller/pci-xgene.c +++ b/drivers/pci/controller/pci-xgene.c @@ -465,7 +465,7 @@ static int xgene_pcie_select_ib_reg(u8 *ib_reg_mask, u6= 4 size) return 1; } =20 - if ((size > SZ_1K) && (size < SZ_4G) && !(*ib_reg_mask & (1 << 0))) { + if ((size > SZ_1K) && (size < SZ_1T) && !(*ib_reg_mask & (1 << 0))) { *ib_reg_mask |=3D (1 << 0); return 0; } @@ -479,28 +479,27 @@ static int xgene_pcie_select_ib_reg(u8 *ib_reg_mask, = u64 size) } =20 static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port, - struct resource_entry *entry, - u8 *ib_reg_mask) + struct of_pci_range *range, u8 *ib_reg_mask) { void __iomem *cfg_base =3D port->cfg_base; struct device *dev =3D port->dev; void __iomem *bar_addr; u32 pim_reg; - u64 cpu_addr =3D entry->res->start; - u64 pci_addr =3D cpu_addr - entry->offset; - u64 size =3D resource_size(entry->res); + u64 cpu_addr =3D range->cpu_addr; + u64 pci_addr =3D range->pci_addr; + u64 size =3D range->size; u64 mask =3D ~(size - 1) | EN_REG; u32 flags =3D PCI_BASE_ADDRESS_MEM_TYPE_64; u32 bar_low; int region; =20 - region =3D xgene_pcie_select_ib_reg(ib_reg_mask, size); + region =3D xgene_pcie_select_ib_reg(ib_reg_mask, range->size); if (region < 0) { dev_warn(dev, "invalid pcie dma-range config\n"); return; } =20 - if (entry->res->flags & IORESOURCE_PREFETCH) + if (range->flags & IORESOURCE_PREFETCH) flags |=3D PCI_BASE_ADDRESS_MEM_PREFETCH; =20 bar_low =3D pcie_bar_low_val((u32)cpu_addr, flags); @@ -531,13 +530,25 @@ static void xgene_pcie_setup_ib_reg(struct xgene_pcie= _port *port, =20 static int xgene_pcie_parse_map_dma_ranges(struct xgene_pcie_port *port) { - struct pci_host_bridge *bridge =3D pci_host_bridge_from_priv(port); - struct resource_entry *entry; + struct device_node *np =3D port->node; + struct of_pci_range range; + struct of_pci_range_parser parser; + struct device *dev =3D port->dev; u8 ib_reg_mask =3D 0; =20 - resource_list_for_each_entry(entry, &bridge->dma_ranges) - xgene_pcie_setup_ib_reg(port, entry, &ib_reg_mask); + if (of_pci_dma_range_parser_init(&parser, np)) { + dev_err(dev, "missing dma-ranges property\n"); + return -EINVAL; + } + + /* Get the dma-ranges from DT */ + for_each_of_pci_range(&parser, &range) { + u64 end =3D range.cpu_addr + range.size - 1; =20 + dev_dbg(dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n", + range.flags, range.cpu_addr, end, range.pci_addr); + xgene_pcie_setup_ib_reg(port, &range, &ib_reg_mask); + } return 0; } =20 diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_= hpc.c index 1d3108e6c128..0e765e0644c2 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -98,6 +98,8 @@ static int pcie_poll_cmd(struct controller *ctrl, int tim= eout) if (slot_status & PCI_EXP_SLTSTA_CC) { pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_CC); + ctrl->cmd_busy =3D 0; + smp_mb(); return 1; } msleep(10); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index db864bf634a3..6272b122f400 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1811,6 +1811,18 @@ static void quirk_alder_ioapic(struct pci_dev *pdev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, q= uirk_alder_ioapic); #endif =20 +static void quirk_no_msi(struct pci_dev *dev) +{ + pci_info(dev, "avoiding MSI to work around a hardware defect\n"); + dev->no_msi =3D 1; +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4386, quirk_no_msi); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4387, quirk_no_msi); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4388, quirk_no_msi); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4389, quirk_no_msi); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x438a, quirk_no_msi); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x438b, quirk_no_msi); + static void quirk_pcie_mch(struct pci_dev *pdev) { pdev->no_msi =3D 1; diff --git a/drivers/phy/broadcom/phy-brcm-usb-init.c b/drivers/phy/broadco= m/phy-brcm-usb-init.c index 9391ab42a12b..dd0f66288fbd 100644 --- a/drivers/phy/broadcom/phy-brcm-usb-init.c +++ b/drivers/phy/broadcom/phy-brcm-usb-init.c @@ -79,6 +79,7 @@ =20 enum brcm_family_type { BRCM_FAMILY_3390A0, + BRCM_FAMILY_4908, BRCM_FAMILY_7250B0, BRCM_FAMILY_7271A0, BRCM_FAMILY_7364A0, @@ -96,6 +97,7 @@ enum brcm_family_type { =20 static const char *family_names[BRCM_FAMILY_COUNT] =3D { USB_BRCM_FAMILY(3390A0), + USB_BRCM_FAMILY(4908), USB_BRCM_FAMILY(7250B0), USB_BRCM_FAMILY(7271A0), USB_BRCM_FAMILY(7364A0), @@ -203,6 +205,27 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SEL= ECTOR_COUNT] =3D { USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */ }, + /* 4908 */ + [BRCM_FAMILY_4908] =3D { + 0, /* USB_CTRL_SETUP_SCB1_EN_MASK */ + 0, /* USB_CTRL_SETUP_SCB2_EN_MASK */ + 0, /* USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK */ + 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ + 0, /* USB_CTRL_SETUP_OC3_DISABLE_MASK */ + 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ + 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ + USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, + USB_CTRL_USB_PM_USB_PWRDN_MASK, + 0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */ + 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ + 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ + 0, /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */ + 0, /* USB_CTRL_USB_PM_SOFT_RESET_MASK */ + 0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */ + 0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */ + 0, /* USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK */ + 0, /* USB_CTRL_SETUP ENDIAN bits */ + }, /* 7250b0 */ [BRCM_FAMILY_7250B0] =3D { USB_CTRL_SETUP_SCB1_EN_MASK, @@ -559,6 +582,7 @@ static void brcmusb_usb3_pll_54mhz(struct brcm_usb_init= _params *params) */ switch (params->selected_family) { case BRCM_FAMILY_3390A0: + case BRCM_FAMILY_4908: case BRCM_FAMILY_7250B0: case BRCM_FAMILY_7366C0: case BRCM_FAMILY_74371A0: @@ -1004,6 +1028,18 @@ static const struct brcm_usb_init_ops bcm7445_ops = =3D { .set_dual_select =3D usb_set_dual_select, }; =20 +void brcm_usb_dvr_init_4908(struct brcm_usb_init_params *params) +{ + int fam; + + fam =3D BRCM_FAMILY_4908; + params->selected_family =3D fam; + params->usb_reg_bits_map =3D + &usb_reg_bits_map_table[fam][0]; + params->family_name =3D family_names[fam]; + params->ops =3D &bcm7445_ops; +} + void brcm_usb_dvr_init_7445(struct brcm_usb_init_params *params) { int fam; diff --git a/drivers/phy/broadcom/phy-brcm-usb-init.h b/drivers/phy/broadco= m/phy-brcm-usb-init.h index a39f30fa2e99..1ccb5ddab865 100644 --- a/drivers/phy/broadcom/phy-brcm-usb-init.h +++ b/drivers/phy/broadcom/phy-brcm-usb-init.h @@ -64,6 +64,7 @@ struct brcm_usb_init_params { bool suspend_with_clocks; }; =20 +void brcm_usb_dvr_init_4908(struct brcm_usb_init_params *params); void brcm_usb_dvr_init_7445(struct brcm_usb_init_params *params); void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params); void brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params); diff --git a/drivers/phy/broadcom/phy-brcm-usb.c b/drivers/phy/broadcom/phy= -brcm-usb.c index 0f1deb6e0eab..2cb3779fcdf8 100644 --- a/drivers/phy/broadcom/phy-brcm-usb.c +++ b/drivers/phy/broadcom/phy-brcm-usb.c @@ -283,6 +283,15 @@ static const struct attribute_group brcm_usb_phy_group= =3D { .attrs =3D brcm_usb_phy_attrs, }; =20 +static const struct match_chip_info chip_info_4908 =3D { + .init_func =3D &brcm_usb_dvr_init_4908, + .required_regs =3D { + BRCM_REGS_CTRL, + BRCM_REGS_XHCI_EC, + -1, + }, +}; + static const struct match_chip_info chip_info_7216 =3D { .init_func =3D &brcm_usb_dvr_init_7216, .required_regs =3D { @@ -318,7 +327,7 @@ static const struct match_chip_info chip_info_7445 =3D { static const struct of_device_id brcm_usb_dt_ids[] =3D { { .compatible =3D "brcm,bcm4908-usb-phy", - .data =3D &chip_info_7445, + .data =3D &chip_info_4908, }, { .compatible =3D "brcm,bcm7216-usb-phy", diff --git a/drivers/phy/phy-core-mipi-dphy.c b/drivers/phy/phy-core-mipi-d= phy.c index ccb4045685cd..929e86d6558e 100644 --- a/drivers/phy/phy-core-mipi-dphy.c +++ b/drivers/phy/phy-core-mipi-dphy.c @@ -64,10 +64,10 @@ int phy_mipi_dphy_get_default_config(unsigned long pixe= l_clock, cfg->hs_trail =3D max(4 * 8 * ui, 60000 + 4 * 4 * ui); =20 cfg->init =3D 100; - cfg->lpx =3D 60000; + cfg->lpx =3D 50000; cfg->ta_get =3D 5 * cfg->lpx; cfg->ta_go =3D 4 * cfg->lpx; - cfg->ta_sure =3D 2 * cfg->lpx; + cfg->ta_sure =3D cfg->lpx; cfg->wakeup =3D 1000; =20 cfg->hs_clk_rate =3D hs_clk_rate; diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctr= l/mediatek/pinctrl-mtk-common.c index 5f7c421ab6e7..334cb85855a9 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -1038,6 +1038,7 @@ int mtk_pctrl_init(struct platform_device *pdev, node =3D of_parse_phandle(np, "mediatek,pctl-regmap", 0); if (node) { pctl->regmap1 =3D syscon_node_to_regmap(node); + of_node_put(node); if (IS_ERR(pctl->regmap1)) return PTR_ERR(pctl->regmap1); } else if (regmap) { @@ -1051,6 +1052,7 @@ int mtk_pctrl_init(struct platform_device *pdev, node =3D of_parse_phandle(np, "mediatek,pctl-regmap", 1); if (node) { pctl->regmap2 =3D syscon_node_to_regmap(node); + of_node_put(node); if (IS_ERR(pctl->regmap2)) return PTR_ERR(pctl->regmap2); } diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/med= iatek/pinctrl-paris.c index 4c6f6d967b18..da6c2c7f1c0d 100644 --- a/drivers/pinctrl/mediatek/pinctrl-paris.c +++ b/drivers/pinctrl/mediatek/pinctrl-paris.c @@ -96,20 +96,16 @@ static int mtk_pinconf_get(struct pinctrl_dev *pctldev, err =3D hw->soc->bias_get_combo(hw, desc, &pullup, &ret); if (err) goto out; + if (ret =3D=3D MTK_PUPD_SET_R1R0_00) + ret =3D MTK_DISABLE; if (param =3D=3D PIN_CONFIG_BIAS_DISABLE) { - if (ret =3D=3D MTK_PUPD_SET_R1R0_00) - ret =3D MTK_DISABLE; + if (ret !=3D MTK_DISABLE) + err =3D -EINVAL; } else if (param =3D=3D PIN_CONFIG_BIAS_PULL_UP) { - /* When desire to get pull-up value, return - * error if current setting is pull-down - */ - if (!pullup) + if (!pullup || ret =3D=3D MTK_DISABLE) err =3D -EINVAL; } else if (param =3D=3D PIN_CONFIG_BIAS_PULL_DOWN) { - /* When desire to get pull-down value, return - * error if current setting is pull-up - */ - if (pullup) + if (pullup || ret =3D=3D MTK_DISABLE) err =3D -EINVAL; } } else { @@ -188,8 +184,7 @@ static int mtk_pinconf_get(struct pinctrl_dev *pctldev, } =20 static int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, - enum pin_config_param param, - enum pin_config_param arg) + enum pin_config_param param, u32 arg) { struct mtk_pinctrl *hw =3D pinctrl_dev_get_drvdata(pctldev); const struct mtk_pin_desc *desc; @@ -586,6 +581,9 @@ ssize_t mtk_pctrl_show_one_pin(struct mtk_pinctrl *hw, if (gpio >=3D hw->soc->npins) return -EINVAL; =20 + if (mtk_is_virt_gpio(hw, gpio)) + return -EINVAL; + desc =3D (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; pinmux =3D mtk_pctrl_get_pinmux(hw, gpio); if (pinmux >=3D hw->soc->nfuncs) @@ -737,10 +735,10 @@ static int mtk_pconf_group_get(struct pinctrl_dev *pc= tldev, unsigned group, unsigned long *config) { struct mtk_pinctrl *hw =3D pinctrl_dev_get_drvdata(pctldev); + struct mtk_pinctrl_group *grp =3D &hw->groups[group]; =20 - *config =3D hw->groups[group].config; - - return 0; + /* One pin per group only */ + return mtk_pinconf_get(pctldev, grp->pin, config); } =20 static int mtk_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, @@ -756,8 +754,6 @@ static int mtk_pconf_group_set(struct pinctrl_dev *pctl= dev, unsigned group, pinconf_to_config_argument(configs[i])); if (ret < 0) return ret; - - grp->config =3D configs[i]; } =20 return 0; @@ -989,7 +985,7 @@ int mtk_paris_pinctrl_probe(struct platform_device *pde= v, hw->nbase =3D hw->soc->nbase_names; =20 if (of_find_property(hw->dev->of_node, - "mediatek,rsel_resistance_in_si_unit", NULL)) + "mediatek,rsel-resistance-in-si-unit", NULL)) hw->rsel_si_unit =3D true; else hw->rsel_si_unit =3D false; diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/no= madik/pinctrl-nomadik.c index 39828e9c3120..4757bf964d3c 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -1883,8 +1883,10 @@ static int nmk_pinctrl_probe(struct platform_device = *pdev) } =20 prcm_np =3D of_parse_phandle(np, "prcm", 0); - if (prcm_np) + if (prcm_np) { npct->prcm_base =3D of_iomap(prcm_np, 0); + of_node_put(prcm_np); + } if (!npct->prcm_base) { if (version =3D=3D PINCTRL_NMK_STN8815) { dev_info(&pdev->dev, diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c b/drivers/pinctrl/nu= voton/pinctrl-npcm7xx.c index 4d81908d6725..41136f63014a 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c @@ -78,7 +78,6 @@ struct npcm7xx_gpio { struct gpio_chip gc; int irqbase; int irq; - void *priv; struct irq_chip irq_chip; u32 pinctrl_id; int (*direction_input)(struct gpio_chip *chip, unsigned offset); @@ -226,7 +225,7 @@ static void npcmgpio_irq_handler(struct irq_desc *desc) chained_irq_enter(chip, desc); sts =3D ioread32(bank->base + NPCM7XX_GP_N_EVST); en =3D ioread32(bank->base + NPCM7XX_GP_N_EVEN); - dev_dbg(chip->parent_device, "=3D=3D> got irq sts %.8x %.8x\n", sts, + dev_dbg(bank->gc.parent, "=3D=3D> got irq sts %.8x %.8x\n", sts, en); =20 sts &=3D en; @@ -241,33 +240,33 @@ static int npcmgpio_set_irq_type(struct irq_data *d, = unsigned int type) gpiochip_get_data(irq_data_get_irq_chip_data(d)); unsigned int gpio =3D BIT(d->hwirq); =20 - dev_dbg(d->chip->parent_device, "setirqtype: %u.%u =3D %u\n", gpio, + dev_dbg(bank->gc.parent, "setirqtype: %u.%u =3D %u\n", gpio, d->irq, type); switch (type) { case IRQ_TYPE_EDGE_RISING: - dev_dbg(d->chip->parent_device, "edge.rising\n"); + dev_dbg(bank->gc.parent, "edge.rising\n"); npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_EVBE, gpio); npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); break; case IRQ_TYPE_EDGE_FALLING: - dev_dbg(d->chip->parent_device, "edge.falling\n"); + dev_dbg(bank->gc.parent, "edge.falling\n"); npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_EVBE, gpio); npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); break; case IRQ_TYPE_EDGE_BOTH: - dev_dbg(d->chip->parent_device, "edge.both\n"); + dev_dbg(bank->gc.parent, "edge.both\n"); npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_EVBE, gpio); break; case IRQ_TYPE_LEVEL_LOW: - dev_dbg(d->chip->parent_device, "level.low\n"); + dev_dbg(bank->gc.parent, "level.low\n"); npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); break; case IRQ_TYPE_LEVEL_HIGH: - dev_dbg(d->chip->parent_device, "level.high\n"); + dev_dbg(bank->gc.parent, "level.high\n"); npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); break; default: - dev_dbg(d->chip->parent_device, "invalid irq type\n"); + dev_dbg(bank->gc.parent, "invalid irq type\n"); return -EINVAL; } =20 @@ -289,7 +288,7 @@ static void npcmgpio_irq_ack(struct irq_data *d) gpiochip_get_data(irq_data_get_irq_chip_data(d)); unsigned int gpio =3D d->hwirq; =20 - dev_dbg(d->chip->parent_device, "irq_ack: %u.%u\n", gpio, d->irq); + dev_dbg(bank->gc.parent, "irq_ack: %u.%u\n", gpio, d->irq); iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVST); } =20 @@ -301,7 +300,7 @@ static void npcmgpio_irq_mask(struct irq_data *d) unsigned int gpio =3D d->hwirq; =20 /* Clear events */ - dev_dbg(d->chip->parent_device, "irq_mask: %u.%u\n", gpio, d->irq); + dev_dbg(bank->gc.parent, "irq_mask: %u.%u\n", gpio, d->irq); iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVENC); } =20 @@ -313,7 +312,7 @@ static void npcmgpio_irq_unmask(struct irq_data *d) unsigned int gpio =3D d->hwirq; =20 /* Enable events */ - dev_dbg(d->chip->parent_device, "irq_unmask: %u.%u\n", gpio, d->irq); + dev_dbg(bank->gc.parent, "irq_unmask: %u.%u\n", gpio, d->irq); iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVENS); } =20 @@ -323,7 +322,7 @@ static unsigned int npcmgpio_irq_startup(struct irq_dat= a *d) unsigned int gpio =3D d->hwirq; =20 /* active-high, input, clear interrupt, enable interrupt */ - dev_dbg(d->chip->parent_device, "startup: %u.%u\n", gpio, d->irq); + dev_dbg(gc->parent, "startup: %u.%u\n", gpio, d->irq); npcmgpio_direction_input(gc, gpio); npcmgpio_irq_ack(d); npcmgpio_irq_unmask(d); @@ -905,7 +904,7 @@ static struct npcm7xx_func npcm7xx_funcs[] =3D { #define DRIVE_STRENGTH_HI_SHIFT 12 #define DRIVE_STRENGTH_MASK 0x0000FF00 =20 -#define DS(lo, hi) (((lo) << DRIVE_STRENGTH_LO_SHIFT) | \ +#define DSTR(lo, hi) (((lo) << DRIVE_STRENGTH_LO_SHIFT) | \ ((hi) << DRIVE_STRENGTH_HI_SHIFT)) #define DSLO(x) (((x) >> DRIVE_STRENGTH_LO_SHIFT) & 0xF) #define DSHI(x) (((x) >> DRIVE_STRENGTH_HI_SHIFT) & 0xF) @@ -925,31 +924,31 @@ struct npcm7xx_pincfg { static const struct npcm7xx_pincfg pincfg[] =3D { /* PIN FUNCTION 1 FUNCTION 2 FUNCTION 3 FLAGS */ NPCM7XX_PINCFG(0, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, = 0), - NPCM7XX_PINCFG(1, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, = DS(8, 12)), - NPCM7XX_PINCFG(2, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, = DS(8, 12)), + NPCM7XX_PINCFG(1, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, = DSTR(8, 12)), + NPCM7XX_PINCFG(2, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, = DSTR(8, 12)), NPCM7XX_PINCFG(3, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, = 0), NPCM7XX_PINCFG(4, iox2, MFSEL3, 14, smb1d, I2CSEGSEL, 7, none, NONE, 0,= SLEW), NPCM7XX_PINCFG(5, iox2, MFSEL3, 14, smb1d, I2CSEGSEL, 7, none, NONE, 0,= SLEW), NPCM7XX_PINCFG(6, iox2, MFSEL3, 14, smb2d, I2CSEGSEL, 10, none, NONE, = 0, SLEW), NPCM7XX_PINCFG(7, iox2, MFSEL3, 14, smb2d, I2CSEGSEL, 10, none, NONE, = 0, SLEW), - NPCM7XX_PINCFG(8, lkgpo1, FLOCKR1, 4, none, NONE, 0, none, NO= NE, 0, DS(8, 12)), - NPCM7XX_PINCFG(9, lkgpo2, FLOCKR1, 8, none, NONE, 0, none, NO= NE, 0, DS(8, 12)), - NPCM7XX_PINCFG(10, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, = DS(8, 12)), - NPCM7XX_PINCFG(11, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, = DS(8, 12)), + NPCM7XX_PINCFG(8, lkgpo1, FLOCKR1, 4, none, NONE, 0, none, NO= NE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(9, lkgpo2, FLOCKR1, 8, none, NONE, 0, none, NO= NE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(10, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, = DSTR(8, 12)), + NPCM7XX_PINCFG(11, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, = DSTR(8, 12)), NPCM7XX_PINCFG(12, gspi, MFSEL1, 24, smb5b, I2CSEGSEL, 19, none, NONE,= 0, SLEW), NPCM7XX_PINCFG(13, gspi, MFSEL1, 24, smb5b, I2CSEGSEL, 19, none, NONE,= 0, SLEW), NPCM7XX_PINCFG(14, gspi, MFSEL1, 24, smb5c, I2CSEGSEL, 20, none, NONE, = 0, SLEW), NPCM7XX_PINCFG(15, gspi, MFSEL1, 24, smb5c, I2CSEGSEL, 20, none, NONE, = 0, SLEW), - NPCM7XX_PINCFG(16, lkgpo0, FLOCKR1, 0, none, NONE, 0, none, NO= NE, 0, DS(8, 12)), - NPCM7XX_PINCFG(17, pspi2, MFSEL3, 13, smb4den, I2CSEGSEL, 23, n= one, NONE, 0, DS(8, 12)), - NPCM7XX_PINCFG(18, pspi2, MFSEL3, 13, smb4b, I2CSEGSEL, 14, none, = NONE, 0, DS(8, 12)), - NPCM7XX_PINCFG(19, pspi2, MFSEL3, 13, smb4b, I2CSEGSEL, 14, none, = NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(16, lkgpo0, FLOCKR1, 0, none, NONE, 0, none, NO= NE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(17, pspi2, MFSEL3, 13, smb4den, I2CSEGSEL, 23, n= one, NONE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(18, pspi2, MFSEL3, 13, smb4b, I2CSEGSEL, 14, none, = NONE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(19, pspi2, MFSEL3, 13, smb4b, I2CSEGSEL, 14, none, = NONE, 0, DSTR(8, 12)), NPCM7XX_PINCFG(20, smb4c, I2CSEGSEL, 15, smb15, MFSEL3, 8, none, = NONE, 0, 0), NPCM7XX_PINCFG(21, smb4c, I2CSEGSEL, 15, smb15, MFSEL3, 8, none, = NONE, 0, 0), NPCM7XX_PINCFG(22, smb4d, I2CSEGSEL, 16, smb14, MFSEL3, 7, non= e, NONE, 0, 0), NPCM7XX_PINCFG(23, smb4d, I2CSEGSEL, 16, smb14, MFSEL3, 7, non= e, NONE, 0, 0), - NPCM7XX_PINCFG(24, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, = DS(8, 12)), - NPCM7XX_PINCFG(25, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, = DS(8, 12)), + NPCM7XX_PINCFG(24, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, = DSTR(8, 12)), + NPCM7XX_PINCFG(25, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, = DSTR(8, 12)), NPCM7XX_PINCFG(26, smb5, MFSEL1, 2, none, NONE, 0, none, NONE, 0, = 0), NPCM7XX_PINCFG(27, smb5, MFSEL1, 2, none, NONE, 0, none, NONE, 0, = 0), NPCM7XX_PINCFG(28, smb4, MFSEL1, 1, none, NONE, 0, none, NONE, 0, = 0), @@ -965,12 +964,12 @@ static const struct npcm7xx_pincfg pincfg[] =3D { NPCM7XX_PINCFG(39, smb3b, I2CSEGSEL, 11, none, NONE, 0, none, NONE, 0, = SLEW), NPCM7XX_PINCFG(40, smb3b, I2CSEGSEL, 11, none, NONE, 0, none, NONE, 0, = SLEW), NPCM7XX_PINCFG(41, bmcuart0a, MFSEL1, 9, none, NONE, 0, none, NO= NE, 0, 0), - NPCM7XX_PINCFG(42, bmcuart0a, MFSEL1, 9, none, NONE, 0, none, NO= NE, 0, DS(2, 4) | GPO), + NPCM7XX_PINCFG(42, bmcuart0a, MFSEL1, 9, none, NONE, 0, none, NO= NE, 0, DSTR(2, 4) | GPO), NPCM7XX_PINCFG(43, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, bmcuart1, = MFSEL3, 24, 0), NPCM7XX_PINCFG(44, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, bmcuart1, = MFSEL3, 24, 0), NPCM7XX_PINCFG(45, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE,= 0, 0), - NPCM7XX_PINCFG(46, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE,= 0, DS(2, 8)), - NPCM7XX_PINCFG(47, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE,= 0, DS(2, 8)), + NPCM7XX_PINCFG(46, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE,= 0, DSTR(2, 8)), + NPCM7XX_PINCFG(47, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE,= 0, DSTR(2, 8)), NPCM7XX_PINCFG(48, uart2, MFSEL1, 11, bmcuart0b, MFSEL4, 1, none, = NONE, 0, GPO), NPCM7XX_PINCFG(49, uart2, MFSEL1, 11, bmcuart0b, MFSEL4, 1, none, = NONE, 0, 0), NPCM7XX_PINCFG(50, uart2, MFSEL1, 11, none, NONE, 0, none, NONE,= 0, 0), @@ -980,8 +979,8 @@ static const struct npcm7xx_pincfg pincfg[] =3D { NPCM7XX_PINCFG(54, uart2, MFSEL1, 11, none, NONE, 0, none, NONE,= 0, 0), NPCM7XX_PINCFG(55, uart2, MFSEL1, 11, none, NONE, 0, none, NONE,= 0, 0), NPCM7XX_PINCFG(56, r1err, MFSEL1, 12, none, NONE, 0, none, NONE, 0, = 0), - NPCM7XX_PINCFG(57, r1md, MFSEL1, 13, none, NONE, 0, n= one, NONE, 0, DS(2, 4)), - NPCM7XX_PINCFG(58, r1md, MFSEL1, 13, none, NONE, 0, none, NO= NE, 0, DS(2, 4)), + NPCM7XX_PINCFG(57, r1md, MFSEL1, 13, none, NONE, 0, n= one, NONE, 0, DSTR(2, 4)), + NPCM7XX_PINCFG(58, r1md, MFSEL1, 13, none, NONE, 0, none, NO= NE, 0, DSTR(2, 4)), NPCM7XX_PINCFG(59, smb3d, I2CSEGSEL, 13, none, NONE, 0, none, NONE, 0, = 0), NPCM7XX_PINCFG(60, smb3d, I2CSEGSEL, 13, none, NONE, 0, none, NONE, 0, = 0), NPCM7XX_PINCFG(61, uart1, MFSEL1, 10, none, NONE, 0, none, NONE, 0= , GPO), @@ -1004,19 +1003,19 @@ static const struct npcm7xx_pincfg pincfg[] =3D { NPCM7XX_PINCFG(77, fanin13, MFSEL2, 13, none, NONE, 0, none, NO= NE, 0, 0), NPCM7XX_PINCFG(78, fanin14, MFSEL2, 14, none, NONE, 0, none, NO= NE, 0, 0), NPCM7XX_PINCFG(79, fanin15, MFSEL2, 15, none, NONE, 0, none, NO= NE, 0, 0), - NPCM7XX_PINCFG(80, pwm0, MFSEL2, 16, none, NONE, 0, none, NONE, 0= , DS(4, 8)), - NPCM7XX_PINCFG(81, pwm1, MFSEL2, 17, none, NONE, 0, none, NONE, 0= , DS(4, 8)), - NPCM7XX_PINCFG(82, pwm2, MFSEL2, 18, none, NONE, 0, none, NONE, 0= , DS(4, 8)), - NPCM7XX_PINCFG(83, pwm3, MFSEL2, 19, none, NONE, 0, none, NONE, 0= , DS(4, 8)), - NPCM7XX_PINCFG(84, r2, MFSEL1, 14, none, NONE, 0, n= one, NONE, 0, DS(8, 12) | SLEW), - NPCM7XX_PINCFG(85, r2, MFSEL1, 14, none, NONE, 0, n= one, NONE, 0, DS(8, 12) | SLEW), - NPCM7XX_PINCFG(86, r2, MFSEL1, 14, none, NONE, 0, n= one, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(80, pwm0, MFSEL2, 16, none, NONE, 0, none, NONE, 0= , DSTR(4, 8)), + NPCM7XX_PINCFG(81, pwm1, MFSEL2, 17, none, NONE, 0, none, NONE, 0= , DSTR(4, 8)), + NPCM7XX_PINCFG(82, pwm2, MFSEL2, 18, none, NONE, 0, none, NONE, 0= , DSTR(4, 8)), + NPCM7XX_PINCFG(83, pwm3, MFSEL2, 19, none, NONE, 0, none, NONE, 0= , DSTR(4, 8)), + NPCM7XX_PINCFG(84, r2, MFSEL1, 14, none, NONE, 0, n= one, NONE, 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(85, r2, MFSEL1, 14, none, NONE, 0, n= one, NONE, 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(86, r2, MFSEL1, 14, none, NONE, 0, n= one, NONE, 0, DSTR(8, 12) | SLEW), NPCM7XX_PINCFG(87, r2, MFSEL1, 14, none, NONE, 0, n= one, NONE, 0, 0), NPCM7XX_PINCFG(88, r2, MFSEL1, 14, none, NONE, 0, n= one, NONE, 0, 0), NPCM7XX_PINCFG(89, r2, MFSEL1, 14, none, NONE, 0, n= one, NONE, 0, 0), NPCM7XX_PINCFG(90, r2err, MFSEL1, 15, none, NONE, 0, n= one, NONE, 0, 0), - NPCM7XX_PINCFG(91, r2md, MFSEL1, 16, none, NONE, 0, none, = NONE, 0, DS(2, 4)), - NPCM7XX_PINCFG(92, r2md, MFSEL1, 16, none, NONE, 0, none, = NONE, 0, DS(2, 4)), + NPCM7XX_PINCFG(91, r2md, MFSEL1, 16, none, NONE, 0, none, = NONE, 0, DSTR(2, 4)), + NPCM7XX_PINCFG(92, r2md, MFSEL1, 16, none, NONE, 0, none, = NONE, 0, DSTR(2, 4)), NPCM7XX_PINCFG(93, ga20kbc, MFSEL1, 17, smb5d, I2CSEGSEL, 21, none, = NONE, 0, 0), NPCM7XX_PINCFG(94, ga20kbc, MFSEL1, 17, smb5d, I2CSEGSEL, 21, none, = NONE, 0, 0), NPCM7XX_PINCFG(95, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1,= 26, 0), @@ -1062,34 +1061,34 @@ static const struct npcm7xx_pincfg pincfg[] =3D { NPCM7XX_PINCFG(133, smb10, MFSEL4, 13, none, NONE, 0, none, NONE, 0, = 0), NPCM7XX_PINCFG(134, smb11, MFSEL4, 14, none, NONE, 0, none, NONE, 0, = 0), NPCM7XX_PINCFG(135, smb11, MFSEL4, 14, none, NONE, 0, none, NONE, 0, = 0), - NPCM7XX_PINCFG(136, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, = DS(8, 12) | SLEW), - NPCM7XX_PINCFG(137, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, = DS(8, 12) | SLEW), - NPCM7XX_PINCFG(138, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, = DS(8, 12) | SLEW), - NPCM7XX_PINCFG(139, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, = DS(8, 12) | SLEW), - NPCM7XX_PINCFG(140, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, = DS(8, 12) | SLEW), + NPCM7XX_PINCFG(136, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, = DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(137, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, = DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(138, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, = DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(139, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, = DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(140, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, = DSTR(8, 12) | SLEW), NPCM7XX_PINCFG(141, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, = 0), - NPCM7XX_PINCFG(142, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, = DS(8, 12) | SLEW), + NPCM7XX_PINCFG(142, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, = DSTR(8, 12) | SLEW), NPCM7XX_PINCFG(143, sd1, MFSEL3, 12, sd1pwr, MFSEL4, 5, n= one, NONE, 0, 0), - NPCM7XX_PINCFG(144, pwm4, MFSEL2, 20, none, NONE, 0, none, NONE, 0, = DS(4, 8)), - NPCM7XX_PINCFG(145, pwm5, MFSEL2, 21, none, NONE, 0, none, NONE, 0, = DS(4, 8)), - NPCM7XX_PINCFG(146, pwm6, MFSEL2, 22, none, NONE, 0, none, NONE, 0, = DS(4, 8)), - NPCM7XX_PINCFG(147, pwm7, MFSEL2, 23, none, NONE, 0, none, NONE, 0, = DS(4, 8)), - NPCM7XX_PINCFG(148, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, = DS(8, 12) | SLEW), - NPCM7XX_PINCFG(149, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, = DS(8, 12) | SLEW), - NPCM7XX_PINCFG(150, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, = DS(8, 12) | SLEW), - NPCM7XX_PINCFG(151, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, = DS(8, 12) | SLEW), - NPCM7XX_PINCFG(152, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, = DS(8, 12) | SLEW), + NPCM7XX_PINCFG(144, pwm4, MFSEL2, 20, none, NONE, 0, none, NONE, 0, = DSTR(4, 8)), + NPCM7XX_PINCFG(145, pwm5, MFSEL2, 21, none, NONE, 0, none, NONE, 0, = DSTR(4, 8)), + NPCM7XX_PINCFG(146, pwm6, MFSEL2, 22, none, NONE, 0, none, NONE, 0, = DSTR(4, 8)), + NPCM7XX_PINCFG(147, pwm7, MFSEL2, 23, none, NONE, 0, none, NONE, 0, = DSTR(4, 8)), + NPCM7XX_PINCFG(148, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, = DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(149, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, = DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(150, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, = DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(151, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, = DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(152, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, = DSTR(8, 12) | SLEW), NPCM7XX_PINCFG(153, mmcwp, FLOCKR1, 24, none, NONE, 0, none, NO= NE, 0, 0), /* Z1/A1 */ - NPCM7XX_PINCFG(154, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, = DS(8, 12) | SLEW), + NPCM7XX_PINCFG(154, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, = DSTR(8, 12) | SLEW), NPCM7XX_PINCFG(155, mmccd, MFSEL3, 25, mmcrst, MFSEL4, 6, n= one, NONE, 0, 0), /* Z1/A1 */ - NPCM7XX_PINCFG(156, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, = DS(8, 12) | SLEW), - NPCM7XX_PINCFG(157, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, = DS(8, 12) | SLEW), - NPCM7XX_PINCFG(158, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, = DS(8, 12) | SLEW), - NPCM7XX_PINCFG(159, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, = DS(8, 12) | SLEW), - - NPCM7XX_PINCFG(160, clkout, MFSEL1, 21, none, NONE, 0, n= one, NONE, 0, DS(8, 12) | SLEW), - NPCM7XX_PINCFG(161, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1= , 26, DS(8, 12)), - NPCM7XX_PINCFG(162, serirq, NONE, 0, gpio, MFSEL1, 31, none,= NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(156, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, = DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(157, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, = DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(158, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, = DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(159, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, = DSTR(8, 12) | SLEW), + + NPCM7XX_PINCFG(160, clkout, MFSEL1, 21, none, NONE, 0, n= one, NONE, 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(161, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1= , 26, DSTR(8, 12)), + NPCM7XX_PINCFG(162, serirq, NONE, 0, gpio, MFSEL1, 31, none,= NONE, 0, DSTR(8, 12)), NPCM7XX_PINCFG(163, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1= , 26, 0), NPCM7XX_PINCFG(164, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1= , 26, SLEWLPC), NPCM7XX_PINCFG(165, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1= , 26, SLEWLPC), @@ -1102,25 +1101,25 @@ static const struct npcm7xx_pincfg pincfg[] =3D { NPCM7XX_PINCFG(172, smb6, MFSEL3, 1, none, NONE, 0, none, NONE, 0, = 0), NPCM7XX_PINCFG(173, smb7, MFSEL3, 2, none, NONE, 0, none, NONE, 0, = 0), NPCM7XX_PINCFG(174, smb7, MFSEL3, 2, none, NONE, 0, none, NONE, 0, = 0), - NPCM7XX_PINCFG(175, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none,= NONE, 0, DS(8, 12)), - NPCM7XX_PINCFG(176, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, n= one, NONE, 0, DS(8, 12)), - NPCM7XX_PINCFG(177, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, n= one, NONE, 0, DS(8, 12)), - NPCM7XX_PINCFG(178, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, = DS(8, 12) | SLEW), - NPCM7XX_PINCFG(179, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, = DS(8, 12) | SLEW), - NPCM7XX_PINCFG(180, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, = DS(8, 12) | SLEW), + NPCM7XX_PINCFG(175, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none,= NONE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(176, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, n= one, NONE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(177, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, n= one, NONE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(178, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, = DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(179, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, = DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(180, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, = DSTR(8, 12) | SLEW), NPCM7XX_PINCFG(181, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, = 0), NPCM7XX_PINCFG(182, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, = 0), - NPCM7XX_PINCFG(183, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0,= DS(8, 12) | SLEW), - NPCM7XX_PINCFG(184, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0,= DS(8, 12) | SLEW | GPO), - NPCM7XX_PINCFG(185, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0,= DS(8, 12) | SLEW | GPO), - NPCM7XX_PINCFG(186, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0,= DS(8, 12)), - NPCM7XX_PINCFG(187, spi3cs1, MFSEL4, 17, none, NONE, 0, none, NO= NE, 0, DS(8, 12)), - NPCM7XX_PINCFG(188, spi3quad, MFSEL4, 20, spi3cs2, MFSEL4, 18, n= one, NONE, 0, DS(8, 12) | SLEW), - NPCM7XX_PINCFG(189, spi3quad, MFSEL4, 20, spi3cs3, MFSEL4, 19, n= one, NONE, 0, DS(8, 12) | SLEW), - NPCM7XX_PINCFG(190, gpio, FLOCKR1, 20, nprd_smi, NONE, 0, none, NO= NE, 0, DS(2, 4)), - NPCM7XX_PINCFG(191, none, NONE, 0, none, NONE, 0, none, NONE, 0, = DS(8, 12)), /* XX */ - - NPCM7XX_PINCFG(192, none, NONE, 0, none, NONE, 0, none, NONE, 0, = DS(8, 12)), /* XX */ + NPCM7XX_PINCFG(183, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0,= DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(184, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0,= DSTR(8, 12) | SLEW | GPO), + NPCM7XX_PINCFG(185, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0,= DSTR(8, 12) | SLEW | GPO), + NPCM7XX_PINCFG(186, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0,= DSTR(8, 12)), + NPCM7XX_PINCFG(187, spi3cs1, MFSEL4, 17, none, NONE, 0, none, NO= NE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(188, spi3quad, MFSEL4, 20, spi3cs2, MFSEL4, 18, n= one, NONE, 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(189, spi3quad, MFSEL4, 20, spi3cs3, MFSEL4, 19, n= one, NONE, 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(190, gpio, FLOCKR1, 20, nprd_smi, NONE, 0, none, NO= NE, 0, DSTR(2, 4)), + NPCM7XX_PINCFG(191, none, NONE, 0, none, NONE, 0, none, NONE, 0, = DSTR(8, 12)), /* XX */ + + NPCM7XX_PINCFG(192, none, NONE, 0, none, NONE, 0, none, NONE, 0, = DSTR(8, 12)), /* XX */ NPCM7XX_PINCFG(193, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, = 0), NPCM7XX_PINCFG(194, smb0b, I2CSEGSEL, 0, none, NONE, 0, none, NONE, 0, = 0), NPCM7XX_PINCFG(195, smb0b, I2CSEGSEL, 0, none, NONE, 0, none, NONE, 0, = 0), @@ -1131,11 +1130,11 @@ static const struct npcm7xx_pincfg pincfg[] =3D { NPCM7XX_PINCFG(200, r2, MFSEL1, 14, none, NONE, 0, n= one, NONE, 0, 0), NPCM7XX_PINCFG(201, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, = 0), NPCM7XX_PINCFG(202, smb0c, I2CSEGSEL, 1, none, NONE, 0, none, NONE, 0, = 0), - NPCM7XX_PINCFG(203, faninx, MFSEL3, 3, none, NONE, 0, none, NO= NE, 0, DS(8, 12)), + NPCM7XX_PINCFG(203, faninx, MFSEL3, 3, none, NONE, 0, none, NO= NE, 0, DSTR(8, 12)), NPCM7XX_PINCFG(204, ddc, NONE, 0, gpio, MFSEL3, 22, none, NON= E, 0, SLEW), NPCM7XX_PINCFG(205, ddc, NONE, 0, gpio, MFSEL3, 22, none, NON= E, 0, SLEW), - NPCM7XX_PINCFG(206, ddc, NONE, 0, gpio, MFSEL3, 22, none, NON= E, 0, DS(4, 8)), - NPCM7XX_PINCFG(207, ddc, NONE, 0, gpio, MFSEL3, 22, none, NON= E, 0, DS(4, 8)), + NPCM7XX_PINCFG(206, ddc, NONE, 0, gpio, MFSEL3, 22, none, NON= E, 0, DSTR(4, 8)), + NPCM7XX_PINCFG(207, ddc, NONE, 0, gpio, MFSEL3, 22, none, NON= E, 0, DSTR(4, 8)), NPCM7XX_PINCFG(208, rg2, MFSEL4, 24, ddr, MFSEL3, 26, n= one, NONE, 0, 0), NPCM7XX_PINCFG(209, rg2, MFSEL4, 24, ddr, MFSEL3, 26, n= one, NONE, 0, 0), NPCM7XX_PINCFG(210, rg2, MFSEL4, 24, ddr, MFSEL3, 26, n= one, NONE, 0, 0), @@ -1147,20 +1146,20 @@ static const struct npcm7xx_pincfg pincfg[] =3D { NPCM7XX_PINCFG(216, rg2mdio, MFSEL4, 23, ddr, MFSEL3, 26, n= one, NONE, 0, 0), NPCM7XX_PINCFG(217, rg2mdio, MFSEL4, 23, ddr, MFSEL3, 26, n= one, NONE, 0, 0), NPCM7XX_PINCFG(218, wdog1, MFSEL3, 19, none, NONE, 0, none, NO= NE, 0, 0), - NPCM7XX_PINCFG(219, wdog2, MFSEL3, 20, none, NONE, 0, none, NO= NE, 0, DS(4, 8)), + NPCM7XX_PINCFG(219, wdog2, MFSEL3, 20, none, NONE, 0, none, NO= NE, 0, DSTR(4, 8)), NPCM7XX_PINCFG(220, smb12, MFSEL3, 5, none, NONE, 0, none, NONE, 0, = 0), NPCM7XX_PINCFG(221, smb12, MFSEL3, 5, none, NONE, 0, none, NONE, 0, = 0), NPCM7XX_PINCFG(222, smb13, MFSEL3, 6, none, NONE, 0, none, NO= NE, 0, 0), NPCM7XX_PINCFG(223, smb13, MFSEL3, 6, none, NONE, 0, none, NO= NE, 0, 0), =20 NPCM7XX_PINCFG(224, spix, MFSEL4, 27, none, NONE, 0, none, NONE, = 0, SLEW), - NPCM7XX_PINCFG(225, spix, MFSEL4, 27, none, NONE, 0, none, NONE, = 0, DS(8, 12) | SLEW | GPO), - NPCM7XX_PINCFG(226, spix, MFSEL4, 27, none, NONE, 0, none, NONE, = 0, DS(8, 12) | SLEW | GPO), - NPCM7XX_PINCFG(227, spix, MFSEL4, 27, none, NONE, 0, none, NONE, = 0, DS(8, 12) | SLEW), - NPCM7XX_PINCFG(228, spixcs1, MFSEL4, 28, none, NONE, 0, none, NO= NE, 0, DS(8, 12) | SLEW), - NPCM7XX_PINCFG(229, spix, MFSEL4, 27, none, NONE, 0, none, NONE, = 0, DS(8, 12) | SLEW), - NPCM7XX_PINCFG(230, spix, MFSEL4, 27, none, NONE, 0, none, NONE, = 0, DS(8, 12) | SLEW), - NPCM7XX_PINCFG(231, clkreq, MFSEL4, 9, none, NONE, 0, n= one, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(225, spix, MFSEL4, 27, none, NONE, 0, none, NONE, = 0, DSTR(8, 12) | SLEW | GPO), + NPCM7XX_PINCFG(226, spix, MFSEL4, 27, none, NONE, 0, none, NONE, = 0, DSTR(8, 12) | SLEW | GPO), + NPCM7XX_PINCFG(227, spix, MFSEL4, 27, none, NONE, 0, none, NONE, = 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(228, spixcs1, MFSEL4, 28, none, NONE, 0, none, NO= NE, 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(229, spix, MFSEL4, 27, none, NONE, 0, none, NONE, = 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(230, spix, MFSEL4, 27, none, NONE, 0, none, NONE, = 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(231, clkreq, MFSEL4, 9, none, NONE, 0, n= one, NONE, 0, DSTR(8, 12)), NPCM7XX_PINCFG(253, none, NONE, 0, none, NONE, 0, none, NONE, 0, = GPI), /* SDHC1 power */ NPCM7XX_PINCFG(254, none, NONE, 0, none, NONE, 0, none, NONE, 0, = GPI), /* SDHC2 power */ NPCM7XX_PINCFG(255, none, NONE, 0, none, NONE, 0, none, NONE, 0, = GPI), /* DACOSEL */ @@ -1561,7 +1560,7 @@ static int npcm7xx_get_groups_count(struct pinctrl_de= v *pctldev) { struct npcm7xx_pinctrl *npcm =3D pinctrl_dev_get_drvdata(pctldev); =20 - dev_dbg(npcm->dev, "group size: %d\n", ARRAY_SIZE(npcm7xx_groups)); + dev_dbg(npcm->dev, "group size: %zu\n", ARRAY_SIZE(npcm7xx_groups)); return ARRAY_SIZE(npcm7xx_groups); } =20 diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-ge= neric.c index 22e8d4c4040e..b1db28007986 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -30,10 +30,10 @@ static const struct pin_config_item conf_items[] =3D { PCONFDUMP(PIN_CONFIG_BIAS_BUS_HOLD, "input bias bus hold", NULL, false), PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL, false), PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NU= LL, false), - PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", NULL, false), + PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", "ohms", true= ), PCONFDUMP(PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, - "input bias pull to pin specific state", NULL, false), - PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", NULL, false), + "input bias pull to pin specific state", "ohms", true), + PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", "ohms", true), PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL, f= alse), PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL,= false), PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL, fal= se), diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-in= genic.c index 2712f51eb238..fa6becca1788 100644 --- a/drivers/pinctrl/pinctrl-ingenic.c +++ b/drivers/pinctrl/pinctrl-ingenic.c @@ -119,6 +119,8 @@ struct ingenic_chip_info { unsigned int num_functions; =20 const u32 *pull_ups, *pull_downs; + + const struct regmap_access_table *access_table; }; =20 struct ingenic_pinctrl { @@ -2179,6 +2181,17 @@ static const struct function_desc x1000_functions[] = =3D { { "mac", x1000_mac_groups, ARRAY_SIZE(x1000_mac_groups), }, }; =20 +static const struct regmap_range x1000_access_ranges[] =3D { + regmap_reg_range(0x000, 0x400 - 4), + regmap_reg_range(0x700, 0x800 - 4), +}; + +/* shared with X1500 */ +static const struct regmap_access_table x1000_access_table =3D { + .yes_ranges =3D x1000_access_ranges, + .n_yes_ranges =3D ARRAY_SIZE(x1000_access_ranges), +}; + static const struct ingenic_chip_info x1000_chip_info =3D { .num_chips =3D 4, .reg_offset =3D 0x100, @@ -2189,6 +2202,7 @@ static const struct ingenic_chip_info x1000_chip_info= =3D { .num_functions =3D ARRAY_SIZE(x1000_functions), .pull_ups =3D x1000_pull_ups, .pull_downs =3D x1000_pull_downs, + .access_table =3D &x1000_access_table, }; =20 static int x1500_uart0_data_pins[] =3D { 0x4a, 0x4b, }; @@ -2300,6 +2314,7 @@ static const struct ingenic_chip_info x1500_chip_info= =3D { .num_functions =3D ARRAY_SIZE(x1500_functions), .pull_ups =3D x1000_pull_ups, .pull_downs =3D x1000_pull_downs, + .access_table =3D &x1000_access_table, }; =20 static const u32 x1830_pull_ups[4] =3D { @@ -2506,6 +2521,16 @@ static const struct function_desc x1830_functions[] = =3D { { "mac", x1830_mac_groups, ARRAY_SIZE(x1830_mac_groups), }, }; =20 +static const struct regmap_range x1830_access_ranges[] =3D { + regmap_reg_range(0x0000, 0x4000 - 4), + regmap_reg_range(0x7000, 0x8000 - 4), +}; + +static const struct regmap_access_table x1830_access_table =3D { + .yes_ranges =3D x1830_access_ranges, + .n_yes_ranges =3D ARRAY_SIZE(x1830_access_ranges), +}; + static const struct ingenic_chip_info x1830_chip_info =3D { .num_chips =3D 4, .reg_offset =3D 0x1000, @@ -2516,6 +2541,7 @@ static const struct ingenic_chip_info x1830_chip_info= =3D { .num_functions =3D ARRAY_SIZE(x1830_functions), .pull_ups =3D x1830_pull_ups, .pull_downs =3D x1830_pull_downs, + .access_table =3D &x1830_access_table, }; =20 static const u32 x2000_pull_ups[5] =3D { @@ -2969,6 +2995,17 @@ static const struct function_desc x2000_functions[] = =3D { { "otg", x2000_otg_groups, ARRAY_SIZE(x2000_otg_groups), }, }; =20 +static const struct regmap_range x2000_access_ranges[] =3D { + regmap_reg_range(0x000, 0x500 - 4), + regmap_reg_range(0x700, 0x800 - 4), +}; + +/* shared with X2100 */ +static const struct regmap_access_table x2000_access_table =3D { + .yes_ranges =3D x2000_access_ranges, + .n_yes_ranges =3D ARRAY_SIZE(x2000_access_ranges), +}; + static const struct ingenic_chip_info x2000_chip_info =3D { .num_chips =3D 5, .reg_offset =3D 0x100, @@ -2979,6 +3016,7 @@ static const struct ingenic_chip_info x2000_chip_info= =3D { .num_functions =3D ARRAY_SIZE(x2000_functions), .pull_ups =3D x2000_pull_ups, .pull_downs =3D x2000_pull_downs, + .access_table =3D &x2000_access_table, }; =20 static const u32 x2100_pull_ups[5] =3D { @@ -3189,6 +3227,7 @@ static const struct ingenic_chip_info x2100_chip_info= =3D { .num_functions =3D ARRAY_SIZE(x2100_functions), .pull_ups =3D x2100_pull_ups, .pull_downs =3D x2100_pull_downs, + .access_table =3D &x2000_access_table, }; =20 static u32 ingenic_gpio_read_reg(struct ingenic_gpio_chip *jzgc, u8 reg) @@ -4168,7 +4207,12 @@ static int __init ingenic_pinctrl_probe(struct platf= orm_device *pdev) return PTR_ERR(base); =20 regmap_config =3D ingenic_pinctrl_regmap_config; - regmap_config.max_register =3D chip_info->num_chips * chip_info->reg_offs= et; + if (chip_info->access_table) { + regmap_config.rd_table =3D chip_info->access_table; + regmap_config.wr_table =3D chip_info->access_table; + } else { + regmap_config.max_register =3D chip_info->num_chips * chip_info->reg_off= set - 4; + } =20 jzpc->map =3D devm_regmap_init_mmio(dev, base, ®map_config); if (IS_ERR(jzpc->map)) { diff --git a/drivers/pinctrl/pinctrl-microchip-sgpio.c b/drivers/pinctrl/pi= nctrl-microchip-sgpio.c index 78765faa245a..dfa374195694 100644 --- a/drivers/pinctrl/pinctrl-microchip-sgpio.c +++ b/drivers/pinctrl/pinctrl-microchip-sgpio.c @@ -18,6 +18,7 @@ #include #include #include +#include =20 #include "core.h" #include "pinconf.h" @@ -115,6 +116,7 @@ struct sgpio_priv { u32 clock; u32 __iomem *regs; const struct sgpio_properties *properties; + spinlock_t lock; }; =20 struct sgpio_port_addr { @@ -216,6 +218,7 @@ static void sgpio_output_set(struct sgpio_priv *priv, int value) { unsigned int bit =3D SGPIO_SRC_BITS * addr->bit; + unsigned long flags; u32 clr, set; =20 switch (priv->properties->arch) { @@ -234,7 +237,10 @@ static void sgpio_output_set(struct sgpio_priv *priv, default: return; } + + spin_lock_irqsave(&priv->lock, flags); sgpio_clrsetbits(priv, REG_PORT_CONFIG, addr->port, clr, set); + spin_unlock_irqrestore(&priv->lock, flags); } =20 static int sgpio_output_get(struct sgpio_priv *priv, @@ -562,10 +568,13 @@ static void microchip_sgpio_irq_settype(struct irq_da= ta *data, struct sgpio_bank *bank =3D gpiochip_get_data(chip); unsigned int gpio =3D irqd_to_hwirq(data); struct sgpio_port_addr addr; + unsigned long flags; u32 ena; =20 sgpio_pin_to_addr(bank->priv, gpio, &addr); =20 + spin_lock_irqsave(&bank->priv->lock, flags); + /* Disable interrupt while changing type */ ena =3D sgpio_readl(bank->priv, REG_INT_ENABLE, addr.bit); sgpio_writel(bank->priv, ena & ~BIT(addr.port), REG_INT_ENABLE, addr.bit); @@ -582,6 +591,8 @@ static void microchip_sgpio_irq_settype(struct irq_data= *data, =20 /* Possibly re-enable interrupts */ sgpio_writel(bank->priv, ena, REG_INT_ENABLE, addr.bit); + + spin_unlock_irqrestore(&bank->priv->lock, flags); } =20 static void microchip_sgpio_irq_setreg(struct irq_data *data, @@ -592,13 +603,16 @@ static void microchip_sgpio_irq_setreg(struct irq_dat= a *data, struct sgpio_bank *bank =3D gpiochip_get_data(chip); unsigned int gpio =3D irqd_to_hwirq(data); struct sgpio_port_addr addr; + unsigned long flags; =20 sgpio_pin_to_addr(bank->priv, gpio, &addr); =20 + spin_lock_irqsave(&bank->priv->lock, flags); if (clear) sgpio_clrsetbits(bank->priv, reg, addr.bit, BIT(addr.port), 0); else sgpio_clrsetbits(bank->priv, reg, addr.bit, 0, BIT(addr.port)); + spin_unlock_irqrestore(&bank->priv->lock, flags); } =20 static void microchip_sgpio_irq_mask(struct irq_data *data) @@ -814,6 +828,7 @@ static int microchip_sgpio_probe(struct platform_device= *pdev) return -ENOMEM; =20 priv->dev =3D dev; + spin_lock_init(&priv->lock); =20 reset =3D devm_reset_control_get_optional_shared(&pdev->dev, "switch"); if (IS_ERR(reset)) diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-r= ockchip.c index dc52da94af0b..923ff21a44c0 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -2702,6 +2702,7 @@ static int rockchip_pinctrl_probe(struct platform_dev= ice *pdev) node =3D of_parse_phandle(np, "rockchip,grf", 0); if (node) { info->regmap_base =3D syscon_node_to_regmap(node); + of_node_put(node); if (IS_ERR(info->regmap_base)) return PTR_ERR(info->regmap_base); } else { @@ -2738,6 +2739,7 @@ static int rockchip_pinctrl_probe(struct platform_dev= ice *pdev) node =3D of_parse_phandle(np, "rockchip,pmu", 0); if (node) { info->regmap_pmu =3D syscon_node_to_regmap(node); + of_node_put(node); if (IS_ERR(info->regmap_pmu)) return PTR_ERR(info->regmap_pmu); } diff --git a/drivers/pinctrl/renesas/core.c b/drivers/pinctrl/renesas/core.c index 0d4ea2e22a53..12d41ac017b5 100644 --- a/drivers/pinctrl/renesas/core.c +++ b/drivers/pinctrl/renesas/core.c @@ -741,7 +741,7 @@ static int sh_pfc_suspend_init(struct sh_pfc *pfc) { re= turn 0; } =20 #ifdef DEBUG #define SH_PFC_MAX_REGS 300 -#define SH_PFC_MAX_ENUMS 3000 +#define SH_PFC_MAX_ENUMS 5000 =20 static unsigned int sh_pfc_errors __initdata; static unsigned int sh_pfc_warnings __initdata; @@ -865,7 +865,8 @@ static void __init sh_pfc_check_cfg_reg(const char *drv= name, GENMASK(cfg_reg->reg_width - 1, 0)); =20 if (cfg_reg->field_width) { - n =3D cfg_reg->reg_width / cfg_reg->field_width; + fw =3D cfg_reg->field_width; + n =3D (cfg_reg->reg_width / fw) << fw; /* Skip field checks (done at build time) */ goto check_enum_ids; } diff --git a/drivers/pinctrl/renesas/pfc-r8a77470.c b/drivers/pinctrl/renes= as/pfc-r8a77470.c index e6e5487691c1..cf7153d06a95 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77470.c +++ b/drivers/pinctrl/renesas/pfc-r8a77470.c @@ -2140,7 +2140,7 @@ static const unsigned int vin0_clk_mux[] =3D { VI0_CLK_MARK, }; /* - VIN1 ----------------------------------------------------------------= --- */ -static const union vin_data vin1_data_pins =3D { +static const union vin_data12 vin1_data_pins =3D { .data12 =3D { RCAR_GP_PIN(3, 1), RCAR_GP_PIN(3, 2), RCAR_GP_PIN(3, 3), RCAR_GP_PIN(3, 4), @@ -2150,7 +2150,7 @@ static const union vin_data vin1_data_pins =3D { RCAR_GP_PIN(3, 15), RCAR_GP_PIN(3, 16), }, }; -static const union vin_data vin1_data_mux =3D { +static const union vin_data12 vin1_data_mux =3D { .data12 =3D { VI1_DATA0_MARK, VI1_DATA1_MARK, VI1_DATA2_MARK, VI1_DATA3_MARK, diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c b/drivers/pinct= rl/samsung/pinctrl-exynos-arm64.c index 6b77fd24571e..5c00be179082 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c @@ -504,13 +504,11 @@ static const struct samsung_pin_ctrl exynos850_pin_ct= rl[] __initconst =3D { /* pin-controller instance 0 ALIVE data */ .pin_banks =3D exynos850_pin_banks0, .nr_banks =3D ARRAY_SIZE(exynos850_pin_banks0), - .eint_gpio_init =3D exynos_eint_gpio_init, .eint_wkup_init =3D exynos_eint_wkup_init, }, { /* pin-controller instance 1 CMGP data */ .pin_banks =3D exynos850_pin_banks1, .nr_banks =3D ARRAY_SIZE(exynos850_pin_banks1), - .eint_gpio_init =3D exynos_eint_gpio_init, .eint_wkup_init =3D exynos_eint_wkup_init, }, { /* pin-controller instance 2 AUD data */ diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/sa= msung/pinctrl-samsung.c index 23f355ae9ca0..81d512b9956c 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -1002,6 +1002,16 @@ samsung_pinctrl_get_soc_data_for_of_alias(struct pla= tform_device *pdev) return &(of_data->ctrl[id]); } =20 +static void samsung_banks_of_node_put(struct samsung_pinctrl_drv_data *d) +{ + struct samsung_pin_bank *bank; + unsigned int i; + + bank =3D d->pin_banks; + for (i =3D 0; i < d->nr_banks; ++i, ++bank) + of_node_put(bank->of_node); +} + /* retrieve the soc specific data */ static const struct samsung_pin_ctrl * samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d, @@ -1116,19 +1126,19 @@ static int samsung_pinctrl_probe(struct platform_de= vice *pdev) if (ctrl->retention_data) { drvdata->retention_ctrl =3D ctrl->retention_data->init(drvdata, ctrl->retention_data); - if (IS_ERR(drvdata->retention_ctrl)) - return PTR_ERR(drvdata->retention_ctrl); + if (IS_ERR(drvdata->retention_ctrl)) { + ret =3D PTR_ERR(drvdata->retention_ctrl); + goto err_put_banks; + } } =20 ret =3D samsung_pinctrl_register(pdev, drvdata); if (ret) - return ret; + goto err_put_banks; =20 ret =3D samsung_gpiolib_register(pdev, drvdata); - if (ret) { - samsung_pinctrl_unregister(pdev, drvdata); - return ret; - } + if (ret) + goto err_unregister; =20 if (ctrl->eint_gpio_init) ctrl->eint_gpio_init(drvdata); @@ -1138,6 +1148,12 @@ static int samsung_pinctrl_probe(struct platform_dev= ice *pdev) platform_set_drvdata(pdev, drvdata); =20 return 0; + +err_unregister: + samsung_pinctrl_unregister(pdev, drvdata); +err_put_banks: + samsung_banks_of_node_put(drvdata); + return ret; } =20 /* diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Mak= efile index f901d2e43166..88cbc434c06b 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -2,6 +2,7 @@ =20 # tell define_trace.h where to find the cros ec trace header CFLAGS_cros_ec_trace.o:=3D -I$(src) +CFLAGS_cros_ec_sensorhub_ring.o:=3D -I$(src) =20 obj-$(CONFIG_CHROMEOS_LAPTOP) +=3D chromeos_laptop.o obj-$(CONFIG_CHROMEOS_PSTORE) +=3D chromeos_pstore.o @@ -20,7 +21,7 @@ obj-$(CONFIG_CROS_EC_CHARDEV) +=3D cros_ec_chardev.o obj-$(CONFIG_CROS_EC_LIGHTBAR) +=3D cros_ec_lightbar.o obj-$(CONFIG_CROS_EC_VBC) +=3D cros_ec_vbc.o obj-$(CONFIG_CROS_EC_DEBUGFS) +=3D cros_ec_debugfs.o -cros-ec-sensorhub-objs :=3D cros_ec_sensorhub.o cros_ec_sensorhub_ring.o= cros_ec_trace.o +cros-ec-sensorhub-objs :=3D cros_ec_sensorhub.o cros_ec_sensorhub_ring.o obj-$(CONFIG_CROS_EC_SENSORHUB) +=3D cros-ec-sensorhub.o obj-$(CONFIG_CROS_EC_SYSFS) +=3D cros_ec_sysfs.o obj-$(CONFIG_CROS_USBPD_LOGGER) +=3D cros_usbpd_logger.o diff --git a/drivers/platform/chrome/cros_ec_sensorhub_ring.c b/drivers/pla= tform/chrome/cros_ec_sensorhub_ring.c index 98e37080f760..71948dade0e2 100644 --- a/drivers/platform/chrome/cros_ec_sensorhub_ring.c +++ b/drivers/platform/chrome/cros_ec_sensorhub_ring.c @@ -17,7 +17,8 @@ #include #include =20 -#include "cros_ec_trace.h" +#define CREATE_TRACE_POINTS +#include "cros_ec_sensorhub_trace.h" =20 /* Precision of fixed point for the m values from the filter */ #define M_PRECISION BIT(23) diff --git a/drivers/platform/chrome/cros_ec_sensorhub_trace.h b/drivers/pl= atform/chrome/cros_ec_sensorhub_trace.h new file mode 100644 index 000000000000..57d9b4785969 --- /dev/null +++ b/drivers/platform/chrome/cros_ec_sensorhub_trace.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Trace events for the ChromeOS Sensorhub kernel module + * + * Copyright 2021 Google LLC. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM cros_ec + +#if !defined(_CROS_EC_SENSORHUB_TRACE_H_) || defined(TRACE_HEADER_MULTI_RE= AD) +#define _CROS_EC_SENSORHUB_TRACE_H_ + +#include +#include + +#include + +TRACE_EVENT(cros_ec_sensorhub_timestamp, + TP_PROTO(u32 ec_sample_timestamp, u32 ec_fifo_timestamp, s64 fifo_tim= estamp, + s64 current_timestamp, s64 current_time), + TP_ARGS(ec_sample_timestamp, ec_fifo_timestamp, fifo_timestamp, current_t= imestamp, + current_time), + TP_STRUCT__entry( + __field(u32, ec_sample_timestamp) + __field(u32, ec_fifo_timestamp) + __field(s64, fifo_timestamp) + __field(s64, current_timestamp) + __field(s64, current_time) + __field(s64, delta) + ), + TP_fast_assign( + __entry->ec_sample_timestamp =3D ec_sample_timestamp; + __entry->ec_fifo_timestamp =3D ec_fifo_timestamp; + __entry->fifo_timestamp =3D fifo_timestamp; + __entry->current_timestamp =3D current_timestamp; + __entry->current_time =3D current_time; + __entry->delta =3D current_timestamp - current_time; + ), + TP_printk("ec_ts: %9u, ec_fifo_ts: %9u, fifo_ts: %12lld, curr_ts: %12lld,= curr_time: %12lld, delta %12lld", + __entry->ec_sample_timestamp, + __entry->ec_fifo_timestamp, + __entry->fifo_timestamp, + __entry->current_timestamp, + __entry->current_time, + __entry->delta + ) +); + +TRACE_EVENT(cros_ec_sensorhub_data, + TP_PROTO(u32 ec_sensor_num, u32 ec_fifo_timestamp, s64 fifo_timestamp, + s64 current_timestamp, s64 current_time), + TP_ARGS(ec_sensor_num, ec_fifo_timestamp, fifo_timestamp, current_timesta= mp, current_time), + TP_STRUCT__entry( + __field(u32, ec_sensor_num) + __field(u32, ec_fifo_timestamp) + __field(s64, fifo_timestamp) + __field(s64, current_timestamp) + __field(s64, current_time) + __field(s64, delta) + ), + TP_fast_assign( + __entry->ec_sensor_num =3D ec_sensor_num; + __entry->ec_fifo_timestamp =3D ec_fifo_timestamp; + __entry->fifo_timestamp =3D fifo_timestamp; + __entry->current_timestamp =3D current_timestamp; + __entry->current_time =3D current_time; + __entry->delta =3D current_timestamp - current_time; + ), + TP_printk("ec_num: %4u, ec_fifo_ts: %9u, fifo_ts: %12lld, curr_ts: %12lld= , curr_time: %12lld, delta %12lld", + __entry->ec_sensor_num, + __entry->ec_fifo_timestamp, + __entry->fifo_timestamp, + __entry->current_timestamp, + __entry->current_time, + __entry->delta + ) +); + +TRACE_EVENT(cros_ec_sensorhub_filter, + TP_PROTO(struct cros_ec_sensors_ts_filter_state *state, s64 dx, s64 d= y), + TP_ARGS(state, dx, dy), + TP_STRUCT__entry( + __field(s64, dx) + __field(s64, dy) + __field(s64, median_m) + __field(s64, median_error) + __field(s64, history_len) + __field(s64, x) + __field(s64, y) + ), + TP_fast_assign( + __entry->dx =3D dx; + __entry->dy =3D dy; + __entry->median_m =3D state->median_m; + __entry->median_error =3D state->median_error; + __entry->history_len =3D state->history_len; + __entry->x =3D state->x_offset; + __entry->y =3D state->y_offset; + ), + TP_printk("dx: %12lld. dy: %12lld median_m: %12lld median_error: %12lld l= en: %lld x: %12lld y: %12lld", + __entry->dx, + __entry->dy, + __entry->median_m, + __entry->median_error, + __entry->history_len, + __entry->x, + __entry->y + ) +); + + +#endif /* _CROS_EC_SENSORHUB_TRACE_H_ */ + +/* this part must be outside header guard */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . + +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE cros_ec_sensorhub_trace + +#include diff --git a/drivers/platform/chrome/cros_ec_trace.h b/drivers/platform/chr= ome/cros_ec_trace.h index 7e7cfc98657a..9bb5cd2c98b8 100644 --- a/drivers/platform/chrome/cros_ec_trace.h +++ b/drivers/platform/chrome/cros_ec_trace.h @@ -15,7 +15,6 @@ #include #include #include -#include =20 #include =20 @@ -71,100 +70,6 @@ TRACE_EVENT(cros_ec_request_done, __entry->retval) ); =20 -TRACE_EVENT(cros_ec_sensorhub_timestamp, - TP_PROTO(u32 ec_sample_timestamp, u32 ec_fifo_timestamp, s64 fifo_tim= estamp, - s64 current_timestamp, s64 current_time), - TP_ARGS(ec_sample_timestamp, ec_fifo_timestamp, fifo_timestamp, current_t= imestamp, - current_time), - TP_STRUCT__entry( - __field(u32, ec_sample_timestamp) - __field(u32, ec_fifo_timestamp) - __field(s64, fifo_timestamp) - __field(s64, current_timestamp) - __field(s64, current_time) - __field(s64, delta) - ), - TP_fast_assign( - __entry->ec_sample_timestamp =3D ec_sample_timestamp; - __entry->ec_fifo_timestamp =3D ec_fifo_timestamp; - __entry->fifo_timestamp =3D fifo_timestamp; - __entry->current_timestamp =3D current_timestamp; - __entry->current_time =3D current_time; - __entry->delta =3D current_timestamp - current_time; - ), - TP_printk("ec_ts: %9u, ec_fifo_ts: %9u, fifo_ts: %12lld, curr_ts: %12lld,= curr_time: %12lld, delta %12lld", - __entry->ec_sample_timestamp, - __entry->ec_fifo_timestamp, - __entry->fifo_timestamp, - __entry->current_timestamp, - __entry->current_time, - __entry->delta - ) -); - -TRACE_EVENT(cros_ec_sensorhub_data, - TP_PROTO(u32 ec_sensor_num, u32 ec_fifo_timestamp, s64 fifo_timestamp, - s64 current_timestamp, s64 current_time), - TP_ARGS(ec_sensor_num, ec_fifo_timestamp, fifo_timestamp, current_timesta= mp, current_time), - TP_STRUCT__entry( - __field(u32, ec_sensor_num) - __field(u32, ec_fifo_timestamp) - __field(s64, fifo_timestamp) - __field(s64, current_timestamp) - __field(s64, current_time) - __field(s64, delta) - ), - TP_fast_assign( - __entry->ec_sensor_num =3D ec_sensor_num; - __entry->ec_fifo_timestamp =3D ec_fifo_timestamp; - __entry->fifo_timestamp =3D fifo_timestamp; - __entry->current_timestamp =3D current_timestamp; - __entry->current_time =3D current_time; - __entry->delta =3D current_timestamp - current_time; - ), - TP_printk("ec_num: %4u, ec_fifo_ts: %9u, fifo_ts: %12lld, curr_ts: %12lld= , curr_time: %12lld, delta %12lld", - __entry->ec_sensor_num, - __entry->ec_fifo_timestamp, - __entry->fifo_timestamp, - __entry->current_timestamp, - __entry->current_time, - __entry->delta - ) -); - -TRACE_EVENT(cros_ec_sensorhub_filter, - TP_PROTO(struct cros_ec_sensors_ts_filter_state *state, s64 dx, s64 d= y), - TP_ARGS(state, dx, dy), - TP_STRUCT__entry( - __field(s64, dx) - __field(s64, dy) - __field(s64, median_m) - __field(s64, median_error) - __field(s64, history_len) - __field(s64, x) - __field(s64, y) - ), - TP_fast_assign( - __entry->dx =3D dx; - __entry->dy =3D dy; - __entry->median_m =3D state->median_m; - __entry->median_error =3D state->median_error; - __entry->history_len =3D state->history_len; - __entry->x =3D state->x_offset; - __entry->y =3D state->y_offset; - ), - TP_printk("dx: %12lld. dy: %12lld median_m: %12lld median_error: %12lld l= en: %lld x: %12lld y: %12lld", - __entry->dx, - __entry->dy, - __entry->median_m, - __entry->median_error, - __entry->history_len, - __entry->x, - __entry->y - ) -); - - #endif /* _CROS_EC_TRACE_H_ */ =20 /* this part must be outside header guard */ diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chr= ome/cros_ec_typec.c index 5de0bfb0bc4d..952c1756f59e 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -1075,7 +1075,13 @@ static int cros_typec_probe(struct platform_device *= pdev) return -ENOMEM; =20 typec->dev =3D dev; + typec->ec =3D dev_get_drvdata(pdev->dev.parent); + if (!typec->ec) { + dev_err(dev, "couldn't find parent EC device\n"); + return -ENODEV; + } + platform_set_drvdata(pdev, typec); =20 ret =3D cros_typec_get_cmd_version(typec); diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawe= i-wmi.c index a2d846c4a7ee..eac3e6b4ea11 100644 --- a/drivers/platform/x86/huawei-wmi.c +++ b/drivers/platform/x86/huawei-wmi.c @@ -470,10 +470,17 @@ static DEVICE_ATTR_RW(charge_control_thresholds); =20 static int huawei_wmi_battery_add(struct power_supply *battery) { - device_create_file(&battery->dev, &dev_attr_charge_control_start_threshol= d); - device_create_file(&battery->dev, &dev_attr_charge_control_end_threshold); + int err =3D 0; =20 - return 0; + err =3D device_create_file(&battery->dev, &dev_attr_charge_control_start_= threshold); + if (err) + return err; + + err =3D device_create_file(&battery->dev, &dev_attr_charge_control_end_th= reshold); + if (err) + device_remove_file(&battery->dev, &dev_attr_charge_control_start_thresho= ld); + + return err; } =20 static int huawei_wmi_battery_remove(struct power_supply *battery) diff --git a/drivers/power/reset/gemini-poweroff.c b/drivers/power/reset/ge= mini-poweroff.c index 90e35c07240a..b7f7a8225f22 100644 --- a/drivers/power/reset/gemini-poweroff.c +++ b/drivers/power/reset/gemini-poweroff.c @@ -107,8 +107,8 @@ static int gemini_poweroff_probe(struct platform_device= *pdev) return PTR_ERR(gpw->base); =20 irq =3D platform_get_irq(pdev, 0); - if (!irq) - return -EINVAL; + if (irq < 0) + return irq; =20 gpw->dev =3D dev; =20 diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/= ab8500_chargalg.c index ff4b26b1ceca..b809fa5abbba 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -2019,11 +2019,11 @@ static int ab8500_chargalg_probe(struct platform_de= vice *pdev) psy_cfg.drv_data =3D di; =20 /* Initilialize safety timer */ - hrtimer_init(&di->safety_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); + hrtimer_init(&di->safety_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); di->safety_timer.function =3D ab8500_chargalg_safety_timer_expired; =20 /* Initilialize maintenance timer */ - hrtimer_init(&di->maintenance_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); + hrtimer_init(&di->maintenance_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); di->maintenance_timer.function =3D ab8500_chargalg_maintenance_timer_expired; =20 diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500= _fg.c index 05fe9724ba50..57799a8079d4 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -2545,8 +2545,10 @@ static int ab8500_fg_sysfs_init(struct ab8500_fg *di) ret =3D kobject_init_and_add(&di->fg_kobject, &ab8500_fg_ktype, NULL, "battery"); - if (ret < 0) + if (ret < 0) { + kobject_put(&di->fg_kobject); dev_err(di->dev, "failed to create sysfs entry\n"); + } =20 return ret; } diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/= bq24190_charger.c index 35ff0c8fe96f..16c4876fe5af 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -39,6 +39,7 @@ #define BQ24190_REG_POC_CHG_CONFIG_DISABLE 0x0 #define BQ24190_REG_POC_CHG_CONFIG_CHARGE 0x1 #define BQ24190_REG_POC_CHG_CONFIG_OTG 0x2 +#define BQ24190_REG_POC_CHG_CONFIG_OTG_ALT 0x3 #define BQ24190_REG_POC_SYS_MIN_MASK (BIT(3) | BIT(2) | BIT(1)) #define BQ24190_REG_POC_SYS_MIN_SHIFT 1 #define BQ24190_REG_POC_SYS_MIN_MIN 3000 @@ -550,7 +551,11 @@ static int bq24190_vbus_is_enabled(struct regulator_de= v *dev) pm_runtime_mark_last_busy(bdi->dev); pm_runtime_put_autosuspend(bdi->dev); =20 - return ret ? ret : val =3D=3D BQ24190_REG_POC_CHG_CONFIG_OTG; + if (ret) + return ret; + + return (val =3D=3D BQ24190_REG_POC_CHG_CONFIG_OTG || + val =3D=3D BQ24190_REG_POC_CHG_CONFIG_OTG_ALT); } =20 static const struct regulator_ops bq24190_vbus_ops =3D { diff --git a/drivers/power/supply/sbs-charger.c b/drivers/power/supply/sbs-= charger.c index 6fa65d118ec1..b08f7d0c4181 100644 --- a/drivers/power/supply/sbs-charger.c +++ b/drivers/power/supply/sbs-charger.c @@ -18,6 +18,7 @@ #include #include #include +#include =20 #define SBS_CHARGER_REG_SPEC_INFO 0x11 #define SBS_CHARGER_REG_STATUS 0x13 @@ -209,7 +210,12 @@ static int sbs_probe(struct i2c_client *client, if (ret) return dev_err_probe(&client->dev, ret, "Failed to request irq\n"); } else { - INIT_DELAYED_WORK(&chip->work, sbs_delayed_work); + ret =3D devm_delayed_work_autocancel(&client->dev, &chip->work, + sbs_delayed_work); + if (ret) + return dev_err_probe(&client->dev, ret, + "Failed to init work for polling\n"); + schedule_delayed_work(&chip->work, msecs_to_jiffies(SBS_CHARGER_POLL_TIME)); } @@ -220,15 +226,6 @@ static int sbs_probe(struct i2c_client *client, return 0; } =20 -static int sbs_remove(struct i2c_client *client) -{ - struct sbs_info *chip =3D i2c_get_clientdata(client); - - cancel_delayed_work_sync(&chip->work); - - return 0; -} - #ifdef CONFIG_OF static const struct of_device_id sbs_dt_ids[] =3D { { .compatible =3D "sbs,sbs-charger" }, @@ -245,7 +242,6 @@ MODULE_DEVICE_TABLE(i2c, sbs_id); =20 static struct i2c_driver sbs_driver =3D { .probe =3D sbs_probe, - .remove =3D sbs_remove, .id_table =3D sbs_id, .driver =3D { .name =3D "sbs-charger", diff --git a/drivers/power/supply/wm8350_power.c b/drivers/power/supply/wm8= 350_power.c index e05cee457471..908cfd45d262 100644 --- a/drivers/power/supply/wm8350_power.c +++ b/drivers/power/supply/wm8350_power.c @@ -408,44 +408,112 @@ static const struct power_supply_desc wm8350_usb_des= c =3D { * Initialisation *********************************************************************/ =20 -static void wm8350_init_charger(struct wm8350 *wm8350) +static int wm8350_init_charger(struct wm8350 *wm8350) { + int ret; + /* register our interest in charger events */ - wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, + ret =3D wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, wm8350_charger_handler, 0, "Battery hot", wm8350); - wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, + if (ret) + goto err; + + ret =3D wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, wm8350_charger_handler, 0, "Battery cold", wm8350); - wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, + if (ret) + goto free_chg_bat_hot; + + ret =3D wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, wm8350_charger_handler, 0, "Battery fail", wm8350); - wm8350_register_irq(wm8350, WM8350_IRQ_CHG_TO, + if (ret) + goto free_chg_bat_cold; + + ret =3D wm8350_register_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350_charger_handler, 0, "Charger timeout", wm8350); - wm8350_register_irq(wm8350, WM8350_IRQ_CHG_END, + if (ret) + goto free_chg_bat_fail; + + ret =3D wm8350_register_irq(wm8350, WM8350_IRQ_CHG_END, wm8350_charger_handler, 0, "Charge end", wm8350); - wm8350_register_irq(wm8350, WM8350_IRQ_CHG_START, + if (ret) + goto free_chg_to; + + ret =3D wm8350_register_irq(wm8350, WM8350_IRQ_CHG_START, wm8350_charger_handler, 0, "Charge start", wm8350); - wm8350_register_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, + if (ret) + goto free_chg_end; + + ret =3D wm8350_register_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, wm8350_charger_handler, 0, "Fast charge ready", wm8350); - wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, + if (ret) + goto free_chg_start; + + ret =3D wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350_charger_handler, 0, "Battery <3.9V", wm8350); - wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, + if (ret) + goto free_chg_fast_rdy; + + ret =3D wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350_charger_handler, 0, "Battery <3.1V", wm8350); - wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, + if (ret) + goto free_chg_vbatt_lt_3p9; + + ret =3D wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350_charger_handler, 0, "Battery <2.85V", wm8350); + if (ret) + goto free_chg_vbatt_lt_3p1; =20 /* and supply change events */ - wm8350_register_irq(wm8350, WM8350_IRQ_EXT_USB_FB, + ret =3D wm8350_register_irq(wm8350, WM8350_IRQ_EXT_USB_FB, wm8350_charger_handler, 0, "USB", wm8350); - wm8350_register_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, + if (ret) + goto free_chg_vbatt_lt_2p85; + + ret =3D wm8350_register_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, wm8350_charger_handler, 0, "Wall", wm8350); - wm8350_register_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, + if (ret) + goto free_ext_usb_fb; + + ret =3D wm8350_register_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, wm8350_charger_handler, 0, "Battery", wm8350); + if (ret) + goto free_ext_wall_fb; + + return 0; + +free_ext_wall_fb: + wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, wm8350); +free_ext_usb_fb: + wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB, wm8350); +free_chg_vbatt_lt_2p85: + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350); +free_chg_vbatt_lt_3p1: + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350); +free_chg_vbatt_lt_3p9: + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350); +free_chg_fast_rdy: + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, wm8350); +free_chg_start: + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START, wm8350); +free_chg_end: + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END, wm8350); +free_chg_to: + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350); +free_chg_bat_fail: + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, wm8350); +free_chg_bat_cold: + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, wm8350); +free_chg_bat_hot: + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, wm8350); +err: + return ret; } =20 static void free_charger_irq(struct wm8350 *wm8350) @@ -456,6 +524,7 @@ static void free_charger_irq(struct wm8350 *wm8350) wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350); wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END, wm8350); wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, wm8350); wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350); wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350); wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350); diff --git a/drivers/powercap/dtpm_cpu.c b/drivers/powercap/dtpm_cpu.c index b740866b228d..1e8cac699646 100644 --- a/drivers/powercap/dtpm_cpu.c +++ b/drivers/powercap/dtpm_cpu.c @@ -150,10 +150,17 @@ static int update_pd_power_uw(struct dtpm *dtpm) static void pd_release(struct dtpm *dtpm) { struct dtpm_cpu *dtpm_cpu =3D to_dtpm_cpu(dtpm); + struct cpufreq_policy *policy; =20 if (freq_qos_request_active(&dtpm_cpu->qos_req)) freq_qos_remove_request(&dtpm_cpu->qos_req); =20 + policy =3D cpufreq_cpu_get(dtpm_cpu->cpu); + if (policy) { + for_each_cpu(dtpm_cpu->cpu, policy->related_cpus) + per_cpu(dtpm_per_cpu, dtpm_cpu->cpu) =3D NULL; + } +=09 kfree(dtpm_cpu); } =20 diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c index 35799e6401c9..2f4b11b4dfcd 100644 --- a/drivers/pps/clients/pps-gpio.c +++ b/drivers/pps/clients/pps-gpio.c @@ -169,7 +169,7 @@ static int pps_gpio_probe(struct platform_device *pdev) /* GPIO setup */ ret =3D pps_gpio_setup(dev); if (ret) - return -EINVAL; + return ret; =20 /* IRQ setup */ ret =3D gpiod_to_irq(data->gpio_pin); diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index 0e4bc8b9329d..b6f2cfd15dd2 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -317,11 +317,18 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock= _info *info, } EXPORT_SYMBOL(ptp_clock_register); =20 +static int unregister_vclock(struct device *dev, void *data) +{ + struct ptp_clock *ptp =3D dev_get_drvdata(dev); + + ptp_vclock_unregister(info_to_vclock(ptp->info)); + return 0; +} + int ptp_clock_unregister(struct ptp_clock *ptp) { if (ptp_vclock_in_use(ptp)) { - pr_err("ptp: virtual clock in use\n"); - return -EBUSY; + device_for_each_child(&ptp->dev, NULL, unregister_vclock); } =20 ptp->defunct =3D 1; diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c index 8e461f3baa05..8cc8ae16553c 100644 --- a/drivers/pwm/pwm-lpc18xx-sct.c +++ b/drivers/pwm/pwm-lpc18xx-sct.c @@ -395,12 +395,6 @@ static int lpc18xx_pwm_probe(struct platform_device *p= dev) lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_LIMIT, BIT(lpc18xx_pwm->period_event)); =20 - ret =3D pwmchip_add(&lpc18xx_pwm->chip); - if (ret < 0) { - dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret); - goto disable_pwmclk; - } - for (i =3D 0; i < lpc18xx_pwm->chip.npwm; i++) { struct lpc18xx_pwm_data *data; =20 @@ -410,14 +404,12 @@ static int lpc18xx_pwm_probe(struct platform_device *= pdev) GFP_KERNEL); if (!data) { ret =3D -ENOMEM; - goto remove_pwmchip; + goto disable_pwmclk; } =20 pwm_set_chip_data(pwm, data); } =20 - platform_set_drvdata(pdev, lpc18xx_pwm); - val =3D lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_CTRL); val &=3D ~LPC18XX_PWM_BIDIR; val &=3D ~LPC18XX_PWM_CTRL_HALT; @@ -425,10 +417,16 @@ static int lpc18xx_pwm_probe(struct platform_device *= pdev) val |=3D LPC18XX_PWM_PRE(0); lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL, val); =20 + ret =3D pwmchip_add(&lpc18xx_pwm->chip); + if (ret < 0) { + dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret); + goto disable_pwmclk; + } + + platform_set_drvdata(pdev, lpc18xx_pwm); + return 0; =20 -remove_pwmchip: - pwmchip_remove(&lpc18xx_pwm->chip); disable_pwmclk: clk_disable_unprepare(lpc18xx_pwm->pwm_clk); return ret; diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qco= m_smd-regulator.c index 9fc666107a06..8490aa8eecb1 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -1317,8 +1317,10 @@ static int rpm_reg_probe(struct platform_device *pde= v) =20 for_each_available_child_of_node(dev->of_node, node) { vreg =3D devm_kzalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL); - if (!vreg) + if (!vreg) { + of_node_put(node); return -ENOMEM; + } =20 ret =3D rpm_regulator_init_vreg(vreg, dev, node, rpm, vreg_data); =20 diff --git a/drivers/regulator/rpi-panel-attiny-regulator.c b/drivers/regul= ator/rpi-panel-attiny-regulator.c index ee46bfbf5eee..991b4730d768 100644 --- a/drivers/regulator/rpi-panel-attiny-regulator.c +++ b/drivers/regulator/rpi-panel-attiny-regulator.c @@ -37,11 +37,24 @@ static const struct regmap_config attiny_regmap_config = =3D { static int attiny_lcd_power_enable(struct regulator_dev *rdev) { unsigned int data; + int ret, i; =20 regmap_write(rdev->regmap, REG_POWERON, 1); + msleep(80); + /* Wait for nPWRDWN to go low to indicate poweron is done. */ - regmap_read_poll_timeout(rdev->regmap, REG_PORTB, data, - data & BIT(0), 10, 1000000); + for (i =3D 0; i < 20; i++) { + ret =3D regmap_read(rdev->regmap, REG_PORTB, &data); + if (!ret) { + if (data & BIT(0)) + break; + } + usleep_range(10000, 12000); + } + usleep_range(10000, 12000); + + if (ret) + pr_err("%s: regmap_read_poll_timeout failed %d\n", __func__, ret); =20 /* Default to the same orientation as the closed source * firmware used for the panel. Runtime rotation @@ -57,23 +70,34 @@ static int attiny_lcd_power_disable(struct regulator_de= v *rdev) { regmap_write(rdev->regmap, REG_PWM, 0); regmap_write(rdev->regmap, REG_POWERON, 0); - udelay(1); + msleep(30); return 0; } =20 static int attiny_lcd_power_is_enabled(struct regulator_dev *rdev) { unsigned int data; - int ret; + int ret, i; =20 - ret =3D regmap_read(rdev->regmap, REG_POWERON, &data); + for (i =3D 0; i < 10; i++) { + ret =3D regmap_read(rdev->regmap, REG_POWERON, &data); + if (!ret) + break; + usleep_range(10000, 12000); + } if (ret < 0) return ret; =20 if (!(data & BIT(0))) return 0; =20 - ret =3D regmap_read(rdev->regmap, REG_PORTB, &data); + for (i =3D 0; i < 10; i++) { + ret =3D regmap_read(rdev->regmap, REG_PORTB, &data); + if (!ret) + break; + usleep_range(10000, 12000); + } + if (ret < 0) return ret; =20 @@ -103,20 +127,32 @@ static int attiny_update_status(struct backlight_devi= ce *bl) { struct regmap *regmap =3D bl_get_data(bl); int brightness =3D bl->props.brightness; + int ret, i; =20 if (bl->props.power !=3D FB_BLANK_UNBLANK || bl->props.fb_blank !=3D FB_BLANK_UNBLANK) brightness =3D 0; =20 - return regmap_write(regmap, REG_PWM, brightness); + for (i =3D 0; i < 10; i++) { + ret =3D regmap_write(regmap, REG_PWM, brightness); + if (!ret) + break; + } + + return ret; } =20 static int attiny_get_brightness(struct backlight_device *bl) { struct regmap *regmap =3D bl_get_data(bl); - int ret, brightness; + int ret, brightness, i; + + for (i =3D 0; i < 10; i++) { + ret =3D regmap_read(regmap, REG_PWM, &brightness); + if (!ret) + break; + } =20 - ret =3D regmap_read(regmap, REG_PWM, &brightness); if (ret) return ret; =20 @@ -166,7 +202,7 @@ static int attiny_i2c_probe(struct i2c_client *i2c, } =20 regmap_write(regmap, REG_POWERON, 0); - mdelay(1); + msleep(30); =20 config.dev =3D &i2c->dev; config.regmap =3D regmap; diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_= q6v5_adsp.c index 098362e6e233..7c02bc132247 100644 --- a/drivers/remoteproc/qcom_q6v5_adsp.c +++ b/drivers/remoteproc/qcom_q6v5_adsp.c @@ -408,6 +408,7 @@ static int adsp_alloc_memory_region(struct qcom_adsp *a= dsp) } =20 ret =3D of_address_to_resource(node, 0, &r); + of_node_put(node); if (ret) return ret; =20 diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q= 6v5_mss.c index 43ea8455546c..b9ab91540b00 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -1806,18 +1806,20 @@ static int q6v5_alloc_memory_region(struct q6v5 *qp= roc) * reserved memory regions from device's memory-region property. */ child =3D of_get_child_by_name(qproc->dev->of_node, "mba"); - if (!child) + if (!child) { node =3D of_parse_phandle(qproc->dev->of_node, "memory-region", 0); - else + } else { node =3D of_parse_phandle(child, "memory-region", 0); + of_node_put(child); + } =20 ret =3D of_address_to_resource(node, 0, &r); + of_node_put(node); if (ret) { dev_err(qproc->dev, "unable to resolve mba region\n"); return ret; } - of_node_put(node); =20 qproc->mba_phys =3D r.start; qproc->mba_size =3D resource_size(&r); @@ -1828,14 +1830,15 @@ static int q6v5_alloc_memory_region(struct q6v5 *qp= roc) } else { child =3D of_get_child_by_name(qproc->dev->of_node, "mpss"); node =3D of_parse_phandle(child, "memory-region", 0); + of_node_put(child); } =20 ret =3D of_address_to_resource(node, 0, &r); + of_node_put(node); if (ret) { dev_err(qproc->dev, "unable to resolve mpss region\n"); return ret; } - of_node_put(node); =20 qproc->mpss_phys =3D qproc->mpss_reloc =3D r.start; qproc->mpss_size =3D resource_size(&r); diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcns= s.c index 80bbafee9846..9a223d394087 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -500,6 +500,7 @@ static int wcnss_alloc_memory_region(struct qcom_wcnss = *wcnss) } =20 ret =3D of_address_to_resource(node, 0, &r); + of_node_put(node); if (ret) return ret; =20 diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/r= emoteproc_debugfs.c index b5a1e3b697d9..581930483ef8 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -76,7 +76,7 @@ static ssize_t rproc_coredump_write(struct file *filp, int ret, err =3D 0; char buf[20]; =20 - if (count > sizeof(buf)) + if (count < 1 || count > sizeof(buf)) return -EINVAL; =20 ret =3D copy_from_user(buf, user_buf, count); diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index d8e835798153..9edd662c69ac 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -804,9 +804,13 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, s= truct rtc_timer *timer) struct timerqueue_node *next =3D timerqueue_getnext(&rtc->timerqueue); struct rtc_time tm; ktime_t now; + int err; + + err =3D __rtc_read_time(rtc, &tm); + if (err) + return err; =20 timer->enabled =3D 1; - __rtc_read_time(rtc, &tm); now =3D rtc_tm_to_ktime(tm); =20 /* Skip over expired timers */ @@ -820,7 +824,6 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, st= ruct rtc_timer *timer) trace_rtc_timer_enqueue(timer); if (!next || ktime_before(timer->node.expires, next->expires)) { struct rtc_wkalrm alarm; - int err; =20 alarm.time =3D rtc_ktime_to_tm(timer->node.expires); alarm.enabled =3D 1; diff --git a/drivers/rtc/rtc-mc146818-lib.c b/drivers/rtc/rtc-mc146818-lib.c index 2065842f775d..04b05e3b68cb 100644 --- a/drivers/rtc/rtc-mc146818-lib.c +++ b/drivers/rtc/rtc-mc146818-lib.c @@ -176,8 +176,10 @@ int mc146818_set_time(struct rtc_time *time) if (yrs >=3D 100) yrs -=3D 100; =20 - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) - || RTC_ALWAYS_BCD) { + spin_lock_irqsave(&rtc_lock, flags); + save_control =3D CMOS_READ(RTC_CONTROL); + spin_unlock_irqrestore(&rtc_lock, flags); + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { sec =3D bin2bcd(sec); min =3D bin2bcd(min); hrs =3D bin2bcd(hrs); diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index e38ee8848385..bad6a5d9c683 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -350,9 +350,6 @@ static int pl031_probe(struct amba_device *adev, const = struct amba_id *id) } } =20 - if (!adev->irq[0]) - clear_bit(RTC_FEATURE_ALARM, ldata->rtc->features); - device_init_wakeup(&adev->dev, true); ldata->rtc =3D devm_rtc_allocate_device(&adev->dev); if (IS_ERR(ldata->rtc)) { @@ -360,6 +357,9 @@ static int pl031_probe(struct amba_device *adev, const = struct amba_id *id) goto out; } =20 + if (!adev->irq[0]) + clear_bit(RTC_FEATURE_ALARM, ldata->rtc->features); + ldata->rtc->ops =3D ops; ldata->rtc->range_min =3D vendor->range_min; ldata->rtc->range_max =3D vendor->range_max; diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 88c549f257db..65047806a541 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -604,7 +604,7 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc) =20 FNIC_TRACE(fnic_queuecommand, sc->device->host->host_no, tag, sc, io_req, sg_count, cmd_trace, - (((u64)CMD_FLAGS(sc) >> 32) | CMD_STATE(sc))); + (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); =20 /* if only we issued IO, will we have the io lock */ if (io_lock_acquired) @@ -986,8 +986,6 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *= fnic, CMD_SP(sc) =3D NULL; CMD_FLAGS(sc) |=3D FNIC_IO_DONE; =20 - spin_unlock_irqrestore(io_lock, flags); - if (hdr_status !=3D FCPIO_SUCCESS) { atomic64_inc(&fnic_stats->io_stats.io_failures); shost_printk(KERN_ERR, fnic->lport->host, "hdr status =3D %s\n", @@ -996,8 +994,6 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *= fnic, =20 fnic_release_ioreq_buf(fnic, io_req, sc); =20 - mempool_free(io_req, fnic->io_req_pool); - cmd_trace =3D ((u64)hdr_status << 56) | (u64)icmnd_cmpl->scsi_status << 48 | (u64)icmnd_cmpl->flags << 40 | (u64)sc->cmnd[0] << 32 | @@ -1021,6 +1017,12 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fni= c *fnic, } else fnic->lport->host_stats.fcp_control_requests++; =20 + /* Call SCSI completion function to complete the IO */ + scsi_done(sc); + spin_unlock_irqrestore(io_lock, flags); + + mempool_free(io_req, fnic->io_req_pool); + atomic64_dec(&fnic_stats->io_stats.active_ios); if (atomic64_read(&fnic->io_cmpl_skip)) atomic64_dec(&fnic->io_cmpl_skip); @@ -1049,9 +1051,6 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic= *fnic, if(io_duration_time > atomic64_read(&fnic_stats->io_stats.current_max_io= _time)) atomic64_set(&fnic_stats->io_stats.current_max_io_time, io_duration_tim= e); } - - /* Call SCSI completion function to complete the IO */ - scsi_done(sc); } =20 /* fnic_fcpio_itmf_cmpl_handler diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas= /hisi_sas_v3_hw.c index 11a44d9dd9b2..b3bdbea3c955 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -530,7 +530,7 @@ MODULE_PARM_DESC(intr_conv, "interrupt converge enable = (0-1)"); =20 /* permit overriding the host protection capabilities mask (EEDP/T10 PI) */ static int prot_mask; -module_param(prot_mask, int, 0); +module_param(prot_mask, int, 0444); MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=3D0x0= "); =20 static void debugfs_work_handler_v3_hw(struct work_struct *work); diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index a315715b3622..7e0cde710fc3 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -197,7 +197,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_= cmd *qc) task->total_xfer_len =3D qc->nbytes; task->num_scatter =3D qc->n_elem; task->data_dir =3D qc->dma_dir; - } else if (qc->tf.protocol =3D=3D ATA_PROT_NODATA) { + } else if (!ata_is_data(qc->tf.protocol)) { task->data_dir =3D DMA_NONE; } else { for_each_sg(qc->sg, sg, qc->n_elem, si) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt= 3sas_base.c index 0d37c4aca175..c38e68943205 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -5737,14 +5737,13 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *= ioc) */ =20 static int -mpt3sas_check_same_4gb_region(long reply_pool_start_address, u32 pool_sz) +mpt3sas_check_same_4gb_region(dma_addr_t start_address, u32 pool_sz) { - long reply_pool_end_address; + dma_addr_t end_address; =20 - reply_pool_end_address =3D reply_pool_start_address + pool_sz; + end_address =3D start_address + pool_sz - 1; =20 - if (upper_32_bits(reply_pool_start_address) =3D=3D - upper_32_bits(reply_pool_end_address)) + if (upper_32_bits(start_address) =3D=3D upper_32_bits(end_address)) return 1; else return 0; @@ -5805,7 +5804,7 @@ _base_allocate_pcie_sgl_pool(struct MPT3SAS_ADAPTER *= ioc, u32 sz) } =20 if (!mpt3sas_check_same_4gb_region( - (long)ioc->pcie_sg_lookup[i].pcie_sgl, sz)) { + ioc->pcie_sg_lookup[i].pcie_sgl_dma, sz)) { ioc_err(ioc, "PCIE SGLs are not in same 4G !! pcie sgl (0x%p) dma =3D (= 0x%llx)\n", ioc->pcie_sg_lookup[i].pcie_sgl, (unsigned long long) @@ -5860,8 +5859,8 @@ _base_allocate_chain_dma_pool(struct MPT3SAS_ADAPTER = *ioc, u32 sz) GFP_KERNEL, &ctr->chain_buffer_dma); if (!ctr->chain_buffer) return -EAGAIN; - if (!mpt3sas_check_same_4gb_region((long) - ctr->chain_buffer, ioc->chain_segment_sz)) { + if (!mpt3sas_check_same_4gb_region( + ctr->chain_buffer_dma, ioc->chain_segment_sz)) { ioc_err(ioc, "Chain buffers are not in same 4G !!! Chain buff (0x%p) dma =3D (0= x%llx)\n", ctr->chain_buffer, @@ -5897,7 +5896,7 @@ _base_allocate_sense_dma_pool(struct MPT3SAS_ADAPTER = *ioc, u32 sz) GFP_KERNEL, &ioc->sense_dma); if (!ioc->sense) return -EAGAIN; - if (!mpt3sas_check_same_4gb_region((long)ioc->sense, sz)) { + if (!mpt3sas_check_same_4gb_region(ioc->sense_dma, sz)) { dinitprintk(ioc, pr_err( "Bad Sense Pool! sense (0x%p) sense_dma =3D (0x%llx)\n", ioc->sense, (unsigned long long) ioc->sense_dma)); @@ -5930,7 +5929,7 @@ _base_allocate_reply_pool(struct MPT3SAS_ADAPTER *ioc= , u32 sz) &ioc->reply_dma); if (!ioc->reply) return -EAGAIN; - if (!mpt3sas_check_same_4gb_region((long)ioc->reply_free, sz)) { + if (!mpt3sas_check_same_4gb_region(ioc->reply_dma, sz)) { dinitprintk(ioc, pr_err( "Bad Reply Pool! Reply (0x%p) Reply dma =3D (0x%llx)\n", ioc->reply, (unsigned long long) ioc->reply_dma)); @@ -5965,7 +5964,7 @@ _base_allocate_reply_free_dma_pool(struct MPT3SAS_ADA= PTER *ioc, u32 sz) GFP_KERNEL, &ioc->reply_free_dma); if (!ioc->reply_free) return -EAGAIN; - if (!mpt3sas_check_same_4gb_region((long)ioc->reply_free, sz)) { + if (!mpt3sas_check_same_4gb_region(ioc->reply_free_dma, sz)) { dinitprintk(ioc, pr_err("Bad Reply Free Pool! Reply Free (0x%p) Reply Free dma =3D (0= x%llx)\n", ioc->reply_free, (unsigned long long) ioc->reply_free_dma)); @@ -6004,7 +6003,7 @@ _base_allocate_reply_post_free_array(struct MPT3SAS_A= DAPTER *ioc, GFP_KERNEL, &ioc->reply_post_free_array_dma); if (!ioc->reply_post_free_array) return -EAGAIN; - if (!mpt3sas_check_same_4gb_region((long)ioc->reply_post_free_array, + if (!mpt3sas_check_same_4gb_region(ioc->reply_post_free_array_dma, reply_post_free_array_sz)) { dinitprintk(ioc, pr_err( "Bad Reply Free Pool! Reply Free (0x%p) Reply Free dma =3D (0x%llx)\= n", @@ -6069,7 +6068,7 @@ base_alloc_rdpq_dma_pool(struct MPT3SAS_ADAPTER *ioc,= int sz) * resources and set DMA mask to 32 and allocate. */ if (!mpt3sas_check_same_4gb_region( - (long)ioc->reply_post[i].reply_post_free, sz)) { + ioc->reply_post[i].reply_post_free_dma, sz)) { dinitprintk(ioc, ioc_err(ioc, "bad Replypost free pool(0x%p)" "reply_post_free_dma =3D (0x%llx)\n", diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_= hwi.c index 066290dd5756..6332cf23bf6b 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -1783,6 +1783,7 @@ static void pm8001_send_abort_all(struct pm8001_hba_i= nfo *pm8001_ha, ccb->device =3D pm8001_ha_dev; ccb->ccb_tag =3D ccb_tag; ccb->task =3D task; + ccb->n_elem =3D 0; =20 circularQ =3D &pm8001_ha->inbnd_q_tbl[0]; =20 @@ -1844,6 +1845,7 @@ static void pm8001_send_read_log(struct pm8001_hba_in= fo *pm8001_ha, ccb->device =3D pm8001_ha_dev; ccb->ccb_tag =3D ccb_tag; ccb->task =3D task; + ccb->n_elem =3D 0; pm8001_ha_dev->id |=3D NCQ_READ_LOG_FLAG; pm8001_ha_dev->id |=3D NCQ_2ND_RLE_FLAG; =20 @@ -1860,7 +1862,7 @@ static void pm8001_send_read_log(struct pm8001_hba_in= fo *pm8001_ha, =20 sata_cmd.tag =3D cpu_to_le32(ccb_tag); sata_cmd.device_id =3D cpu_to_le32(pm8001_ha_dev->device_id); - sata_cmd.ncqtag_atap_dir_m |=3D ((0x1 << 7) | (0x5 << 9)); + sata_cmd.ncqtag_atap_dir_m =3D cpu_to_le32((0x1 << 7) | (0x5 << 9)); memcpy(&sata_cmd.sata_fis, &fis, sizeof(struct host_to_dev_fis)); =20 res =3D pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, @@ -2421,7 +2423,8 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha= , void *piomb) len =3D sizeof(struct pio_setup_fis); pm8001_dbg(pm8001_ha, IO, "PIO read len =3D %d\n", len); - } else if (t->ata_task.use_ncq) { + } else if (t->ata_task.use_ncq && + t->data_dir !=3D DMA_NONE) { len =3D sizeof(struct set_dev_bits_fis); pm8001_dbg(pm8001_ha, IO, "FPDMA len =3D %d\n", len); @@ -4282,22 +4285,22 @@ static int pm8001_chip_sata_req(struct pm8001_hba_i= nfo *pm8001_ha, u32 opc =3D OPC_INB_SATA_HOST_OPSTART; memset(&sata_cmd, 0, sizeof(sata_cmd)); circularQ =3D &pm8001_ha->inbnd_q_tbl[0]; - if (task->data_dir =3D=3D DMA_NONE) { + + if (task->data_dir =3D=3D DMA_NONE && !task->ata_task.use_ncq) { ATAP =3D 0x04; /* no data*/ pm8001_dbg(pm8001_ha, IO, "no data\n"); } else if (likely(!task->ata_task.device_control_reg_update)) { - if (task->ata_task.dma_xfer) { + if (task->ata_task.use_ncq && + dev->sata_dev.class !=3D ATA_DEV_ATAPI) { + ATAP =3D 0x07; /* FPDMA */ + pm8001_dbg(pm8001_ha, IO, "FPDMA\n"); + } else if (task->ata_task.dma_xfer) { ATAP =3D 0x06; /* DMA */ pm8001_dbg(pm8001_ha, IO, "DMA\n"); } else { ATAP =3D 0x05; /* PIO*/ pm8001_dbg(pm8001_ha, IO, "PIO\n"); } - if (task->ata_task.use_ncq && - dev->sata_dev.class !=3D ATA_DEV_ATAPI) { - ATAP =3D 0x07; /* FPDMA */ - pm8001_dbg(pm8001_ha, IO, "FPDMA\n"); - } } if (task->ata_task.use_ncq && pm8001_get_ncq_tag(task, &hdr_tag)) { task->ata_task.fis.sector_count |=3D (u8) (hdr_tag << 3); @@ -4637,7 +4640,7 @@ int pm8001_chip_ssp_tm_req(struct pm8001_hba_info *pm= 8001_ha, memcpy(sspTMCmd.lun, task->ssp_task.LUN, 8); sspTMCmd.tag =3D cpu_to_le32(ccb->ccb_tag); if (pm8001_ha->chip_id !=3D chip_8001) - sspTMCmd.ds_ads_m =3D 0x08; + sspTMCmd.ds_ads_m =3D cpu_to_le32(0x08); circularQ =3D &pm8001_ha->inbnd_q_tbl[0]; ret =3D pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sspTMCmd, sizeof(sspTMCmd), 0); diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_= hwi.c index ca4820d99dc7..48b0154211c7 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -1202,9 +1202,11 @@ pm80xx_set_thermal_config(struct pm8001_hba_info *pm= 8001_ha) else page_code =3D THERMAL_PAGE_CODE_8H; =20 - payload.cfg_pg[0] =3D (THERMAL_LOG_ENABLE << 9) | - (THERMAL_ENABLE << 8) | page_code; - payload.cfg_pg[1] =3D (LTEMPHIL << 24) | (RTEMPHIL << 8); + payload.cfg_pg[0] =3D + cpu_to_le32((THERMAL_LOG_ENABLE << 9) | + (THERMAL_ENABLE << 8) | page_code); + payload.cfg_pg[1] =3D + cpu_to_le32((LTEMPHIL << 24) | (RTEMPHIL << 8)); =20 pm8001_dbg(pm8001_ha, DEV, "Setting up thermal config. cfg_pg 0 0x%x cfg_pg 1 0x%x\n", @@ -1244,43 +1246,41 @@ pm80xx_set_sas_protocol_timer_config(struct pm8001_= hba_info *pm8001_ha) circularQ =3D &pm8001_ha->inbnd_q_tbl[0]; payload.tag =3D cpu_to_le32(tag); =20 - SASConfigPage.pageCode =3D SAS_PROTOCOL_TIMER_CONFIG_PAGE; - SASConfigPage.MST_MSI =3D 3 << 15; - SASConfigPage.STP_SSP_MCT_TMO =3D (STP_MCT_TMO << 16) | SSP_MCT_TMO; - SASConfigPage.STP_FRM_TMO =3D (SAS_MAX_OPEN_TIME << 24) | - (SMP_MAX_CONN_TIMER << 16) | STP_FRM_TIMER; - SASConfigPage.STP_IDLE_TMO =3D STP_IDLE_TIME; - - if (SASConfigPage.STP_IDLE_TMO > 0x3FFFFFF) - SASConfigPage.STP_IDLE_TMO =3D 0x3FFFFFF; - - - SASConfigPage.OPNRJT_RTRY_INTVL =3D (SAS_MFD << 16) | - SAS_OPNRJT_RTRY_INTVL; - SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO =3D (SAS_DOPNRJT_RTRY_TMO << 16) - | SAS_COPNRJT_RTRY_TMO; - SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR =3D (SAS_DOPNRJT_RTRY_THR << 16) - | SAS_COPNRJT_RTRY_THR; - SASConfigPage.MAX_AIP =3D SAS_MAX_AIP; + SASConfigPage.pageCode =3D cpu_to_le32(SAS_PROTOCOL_TIMER_CONFIG_PAGE); + SASConfigPage.MST_MSI =3D cpu_to_le32(3 << 15); + SASConfigPage.STP_SSP_MCT_TMO =3D + cpu_to_le32((STP_MCT_TMO << 16) | SSP_MCT_TMO); + SASConfigPage.STP_FRM_TMO =3D + cpu_to_le32((SAS_MAX_OPEN_TIME << 24) | + (SMP_MAX_CONN_TIMER << 16) | STP_FRM_TIMER); + SASConfigPage.STP_IDLE_TMO =3D cpu_to_le32(STP_IDLE_TIME); + + SASConfigPage.OPNRJT_RTRY_INTVL =3D + cpu_to_le32((SAS_MFD << 16) | SAS_OPNRJT_RTRY_INTVL); + SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO =3D + cpu_to_le32((SAS_DOPNRJT_RTRY_TMO << 16) | SAS_COPNRJT_RTRY_TMO); + SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR =3D + cpu_to_le32((SAS_DOPNRJT_RTRY_THR << 16) | SAS_COPNRJT_RTRY_THR); + SASConfigPage.MAX_AIP =3D cpu_to_le32(SAS_MAX_AIP); =20 pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.pageCode 0x%08x\n", - SASConfigPage.pageCode); + le32_to_cpu(SASConfigPage.pageCode)); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.MST_MSI 0x%08x\n", - SASConfigPage.MST_MSI); + le32_to_cpu(SASConfigPage.MST_MSI)); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_SSP_MCT_TMO 0x%08x\n", - SASConfigPage.STP_SSP_MCT_TMO); + le32_to_cpu(SASConfigPage.STP_SSP_MCT_TMO)); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_FRM_TMO 0x%08x\n", - SASConfigPage.STP_FRM_TMO); + le32_to_cpu(SASConfigPage.STP_FRM_TMO)); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_IDLE_TMO 0x%08x\n", - SASConfigPage.STP_IDLE_TMO); + le32_to_cpu(SASConfigPage.STP_IDLE_TMO)); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.OPNRJT_RTRY_INTVL 0x%08x\n", - SASConfigPage.OPNRJT_RTRY_INTVL); + le32_to_cpu(SASConfigPage.OPNRJT_RTRY_INTVL)); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO 0x%0= 8x\n", - SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO); + le32_to_cpu(SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO)); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR 0x%0= 8x\n", - SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR); + le32_to_cpu(SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR)); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.MAX_AIP 0x%08x\n", - SASConfigPage.MAX_AIP); + le32_to_cpu(SASConfigPage.MAX_AIP)); =20 memcpy(&payload.cfg_pg, &SASConfigPage, sizeof(SASProtocolTimerConfig_t)); @@ -1406,12 +1406,13 @@ static int pm80xx_encrypt_update(struct pm8001_hba_= info *pm8001_ha) /* Currently only one key is used. New KEK index is 1. * Current KEK index is 1. Store KEK to NVRAM is 1. */ - payload.new_curidx_ksop =3D ((1 << 24) | (1 << 16) | (1 << 8) | - KEK_MGMT_SUBOP_KEYCARDUPDATE); + payload.new_curidx_ksop =3D + cpu_to_le32(((1 << 24) | (1 << 16) | (1 << 8) | + KEK_MGMT_SUBOP_KEYCARDUPDATE)); =20 pm8001_dbg(pm8001_ha, DEV, "Saving Encryption info to flash. payload 0x%x\n", - payload.new_curidx_ksop); + le32_to_cpu(payload.new_curidx_ksop)); =20 rc =3D pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, sizeof(payload), 0); @@ -1800,6 +1801,7 @@ static void pm80xx_send_abort_all(struct pm8001_hba_i= nfo *pm8001_ha, ccb->device =3D pm8001_ha_dev; ccb->ccb_tag =3D ccb_tag; ccb->task =3D task; + ccb->n_elem =3D 0; =20 circularQ =3D &pm8001_ha->inbnd_q_tbl[0]; =20 @@ -1881,7 +1883,7 @@ static void pm80xx_send_read_log(struct pm8001_hba_in= fo *pm8001_ha, =20 sata_cmd.tag =3D cpu_to_le32(ccb_tag); sata_cmd.device_id =3D cpu_to_le32(pm8001_ha_dev->device_id); - sata_cmd.ncqtag_atap_dir_m_dad |=3D ((0x1 << 7) | (0x5 << 9)); + sata_cmd.ncqtag_atap_dir_m_dad =3D cpu_to_le32(((0x1 << 7) | (0x5 << 9))); memcpy(&sata_cmd.sata_fis, &fis, sizeof(struct host_to_dev_fis)); =20 res =3D pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, @@ -2517,7 +2519,8 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, len =3D sizeof(struct pio_setup_fis); pm8001_dbg(pm8001_ha, IO, "PIO read len =3D %d\n", len); - } else if (t->ata_task.use_ncq) { + } else if (t->ata_task.use_ncq && + t->data_dir !=3D DMA_NONE) { len =3D sizeof(struct set_dev_bits_fis); pm8001_dbg(pm8001_ha, IO, "FPDMA len =3D %d\n", len); @@ -4388,13 +4391,15 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba= _info *pm8001_ha, struct ssp_ini_io_start_req ssp_cmd; u32 tag =3D ccb->ccb_tag; int ret; - u64 phys_addr, start_addr, end_addr; + u64 phys_addr, end_addr; u32 end_addr_high, end_addr_low; struct inbound_queue_table *circularQ; u32 q_index, cpu_id; u32 opc =3D OPC_INB_SSPINIIOSTART; + memset(&ssp_cmd, 0, sizeof(ssp_cmd)); memcpy(ssp_cmd.ssp_iu.lun, task->ssp_task.LUN, 8); + /* data address domain added for spcv; set to 0 by host, * used internally by controller * 0 for SAS 1.1 and SAS 2.0 compatible TLR @@ -4405,7 +4410,7 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_i= nfo *pm8001_ha, ssp_cmd.device_id =3D cpu_to_le32(pm8001_dev->device_id); ssp_cmd.tag =3D cpu_to_le32(tag); if (task->ssp_task.enable_first_burst) - ssp_cmd.ssp_iu.efb_prio_attr |=3D 0x80; + ssp_cmd.ssp_iu.efb_prio_attr =3D 0x80; ssp_cmd.ssp_iu.efb_prio_attr |=3D (task->ssp_task.task_prio << 3); ssp_cmd.ssp_iu.efb_prio_attr |=3D (task->ssp_task.task_attr & 7); memcpy(ssp_cmd.ssp_iu.cdb, task->ssp_task.cmd->cmnd, @@ -4437,21 +4442,24 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba= _info *pm8001_ha, ssp_cmd.enc_esgl =3D cpu_to_le32(1<<31); } else if (task->num_scatter =3D=3D 1) { u64 dma_addr =3D sg_dma_address(task->scatter); + ssp_cmd.enc_addr_low =3D cpu_to_le32(lower_32_bits(dma_addr)); ssp_cmd.enc_addr_high =3D cpu_to_le32(upper_32_bits(dma_addr)); ssp_cmd.enc_len =3D cpu_to_le32(task->total_xfer_len); ssp_cmd.enc_esgl =3D 0; + /* Check 4G Boundary */ - start_addr =3D cpu_to_le64(dma_addr); - end_addr =3D (start_addr + ssp_cmd.enc_len) - 1; - end_addr_low =3D cpu_to_le32(lower_32_bits(end_addr)); - end_addr_high =3D cpu_to_le32(upper_32_bits(end_addr)); - if (end_addr_high !=3D ssp_cmd.enc_addr_high) { + end_addr =3D dma_addr + le32_to_cpu(ssp_cmd.enc_len) - 1; + end_addr_low =3D lower_32_bits(end_addr); + end_addr_high =3D upper_32_bits(end_addr); + + if (end_addr_high !=3D le32_to_cpu(ssp_cmd.enc_addr_high)) { pm8001_dbg(pm8001_ha, FAIL, "The sg list address start_addr=3D0x%016llx data_len=3D0x%x end_ad= dr_high=3D0x%08x end_addr_low=3D0x%08x has crossed 4G boundary\n", - start_addr, ssp_cmd.enc_len, + dma_addr, + le32_to_cpu(ssp_cmd.enc_len), end_addr_high, end_addr_low); pm8001_chip_make_sg(task->scatter, 1, ccb->buf_prd); @@ -4460,7 +4468,7 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_i= nfo *pm8001_ha, cpu_to_le32(lower_32_bits(phys_addr)); ssp_cmd.enc_addr_high =3D cpu_to_le32(upper_32_bits(phys_addr)); - ssp_cmd.enc_esgl =3D cpu_to_le32(1<<31); + ssp_cmd.enc_esgl =3D cpu_to_le32(1U<<31); } } else if (task->num_scatter =3D=3D 0) { ssp_cmd.enc_addr_low =3D 0; @@ -4468,8 +4476,10 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_= info *pm8001_ha, ssp_cmd.enc_len =3D cpu_to_le32(task->total_xfer_len); ssp_cmd.enc_esgl =3D 0; } + /* XTS mode. All other fields are 0 */ - ssp_cmd.key_cmode =3D 0x6 << 4; + ssp_cmd.key_cmode =3D cpu_to_le32(0x6 << 4); + /* set tweak values. Should be the start lba */ ssp_cmd.twk_val0 =3D cpu_to_le32((task->ssp_task.cmd->cmnd[2] << 24) | (task->ssp_task.cmd->cmnd[3] << 16) | @@ -4491,20 +4501,22 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba= _info *pm8001_ha, ssp_cmd.esgl =3D cpu_to_le32(1<<31); } else if (task->num_scatter =3D=3D 1) { u64 dma_addr =3D sg_dma_address(task->scatter); + ssp_cmd.addr_low =3D cpu_to_le32(lower_32_bits(dma_addr)); ssp_cmd.addr_high =3D cpu_to_le32(upper_32_bits(dma_addr)); ssp_cmd.len =3D cpu_to_le32(task->total_xfer_len); ssp_cmd.esgl =3D 0; + /* Check 4G Boundary */ - start_addr =3D cpu_to_le64(dma_addr); - end_addr =3D (start_addr + ssp_cmd.len) - 1; - end_addr_low =3D cpu_to_le32(lower_32_bits(end_addr)); - end_addr_high =3D cpu_to_le32(upper_32_bits(end_addr)); - if (end_addr_high !=3D ssp_cmd.addr_high) { + end_addr =3D dma_addr + le32_to_cpu(ssp_cmd.len) - 1; + end_addr_low =3D lower_32_bits(end_addr); + end_addr_high =3D upper_32_bits(end_addr); + if (end_addr_high !=3D le32_to_cpu(ssp_cmd.addr_high)) { pm8001_dbg(pm8001_ha, FAIL, "The sg list address start_addr=3D0x%016llx data_len=3D0x%x end_ad= dr_high=3D0x%08x end_addr_low=3D0x%08x has crossed 4G boundary\n", - start_addr, ssp_cmd.len, + dma_addr, + le32_to_cpu(ssp_cmd.len), end_addr_high, end_addr_low); pm8001_chip_make_sg(task->scatter, 1, ccb->buf_prd); @@ -4538,7 +4550,7 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_inf= o *pm8001_ha, u32 q_index, cpu_id; struct sata_start_req sata_cmd; u32 hdr_tag, ncg_tag =3D 0; - u64 phys_addr, start_addr, end_addr; + u64 phys_addr, end_addr; u32 end_addr_high, end_addr_low; u32 ATAP =3D 0x0; u32 dir; @@ -4550,22 +4562,21 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_i= nfo *pm8001_ha, q_index =3D (u32) (cpu_id) % (pm8001_ha->max_q_num); circularQ =3D &pm8001_ha->inbnd_q_tbl[q_index]; =20 - if (task->data_dir =3D=3D DMA_NONE) { + if (task->data_dir =3D=3D DMA_NONE && !task->ata_task.use_ncq) { ATAP =3D 0x04; /* no data*/ pm8001_dbg(pm8001_ha, IO, "no data\n"); } else if (likely(!task->ata_task.device_control_reg_update)) { - if (task->ata_task.dma_xfer) { + if (task->ata_task.use_ncq && + dev->sata_dev.class !=3D ATA_DEV_ATAPI) { + ATAP =3D 0x07; /* FPDMA */ + pm8001_dbg(pm8001_ha, IO, "FPDMA\n"); + } else if (task->ata_task.dma_xfer) { ATAP =3D 0x06; /* DMA */ pm8001_dbg(pm8001_ha, IO, "DMA\n"); } else { ATAP =3D 0x05; /* PIO*/ pm8001_dbg(pm8001_ha, IO, "PIO\n"); } - if (task->ata_task.use_ncq && - dev->sata_dev.class !=3D ATA_DEV_ATAPI) { - ATAP =3D 0x07; /* FPDMA */ - pm8001_dbg(pm8001_ha, IO, "FPDMA\n"); - } } if (task->ata_task.use_ncq && pm8001_get_ncq_tag(task, &hdr_tag)) { task->ata_task.fis.sector_count |=3D (u8) (hdr_tag << 3); @@ -4599,32 +4610,38 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_i= nfo *pm8001_ha, pm8001_chip_make_sg(task->scatter, ccb->n_elem, ccb->buf_prd); phys_addr =3D ccb->ccb_dma_handle; - sata_cmd.enc_addr_low =3D lower_32_bits(phys_addr); - sata_cmd.enc_addr_high =3D upper_32_bits(phys_addr); + sata_cmd.enc_addr_low =3D + cpu_to_le32(lower_32_bits(phys_addr)); + sata_cmd.enc_addr_high =3D + cpu_to_le32(upper_32_bits(phys_addr)); sata_cmd.enc_esgl =3D cpu_to_le32(1 << 31); } else if (task->num_scatter =3D=3D 1) { u64 dma_addr =3D sg_dma_address(task->scatter); - sata_cmd.enc_addr_low =3D lower_32_bits(dma_addr); - sata_cmd.enc_addr_high =3D upper_32_bits(dma_addr); + + sata_cmd.enc_addr_low =3D + cpu_to_le32(lower_32_bits(dma_addr)); + sata_cmd.enc_addr_high =3D + cpu_to_le32(upper_32_bits(dma_addr)); sata_cmd.enc_len =3D cpu_to_le32(task->total_xfer_len); sata_cmd.enc_esgl =3D 0; + /* Check 4G Boundary */ - start_addr =3D cpu_to_le64(dma_addr); - end_addr =3D (start_addr + sata_cmd.enc_len) - 1; - end_addr_low =3D cpu_to_le32(lower_32_bits(end_addr)); - end_addr_high =3D cpu_to_le32(upper_32_bits(end_addr)); - if (end_addr_high !=3D sata_cmd.enc_addr_high) { + end_addr =3D dma_addr + le32_to_cpu(sata_cmd.enc_len) - 1; + end_addr_low =3D lower_32_bits(end_addr); + end_addr_high =3D upper_32_bits(end_addr); + if (end_addr_high !=3D le32_to_cpu(sata_cmd.enc_addr_high)) { pm8001_dbg(pm8001_ha, FAIL, "The sg list address start_addr=3D0x%016llx data_len=3D0x%x end_ad= dr_high=3D0x%08x end_addr_low=3D0x%08x has crossed 4G boundary\n", - start_addr, sata_cmd.enc_len, + dma_addr, + le32_to_cpu(sata_cmd.enc_len), end_addr_high, end_addr_low); pm8001_chip_make_sg(task->scatter, 1, ccb->buf_prd); phys_addr =3D ccb->ccb_dma_handle; sata_cmd.enc_addr_low =3D - lower_32_bits(phys_addr); + cpu_to_le32(lower_32_bits(phys_addr)); sata_cmd.enc_addr_high =3D - upper_32_bits(phys_addr); + cpu_to_le32(upper_32_bits(phys_addr)); sata_cmd.enc_esgl =3D cpu_to_le32(1 << 31); } @@ -4635,7 +4652,8 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_inf= o *pm8001_ha, sata_cmd.enc_esgl =3D 0; } /* XTS mode. All other fields are 0 */ - sata_cmd.key_index_mode =3D 0x6 << 4; + sata_cmd.key_index_mode =3D cpu_to_le32(0x6 << 4); + /* set tweak values. Should be the start lba */ sata_cmd.twk_val0 =3D cpu_to_le32((sata_cmd.sata_fis.lbal_exp << 24) | @@ -4661,31 +4679,31 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_i= nfo *pm8001_ha, phys_addr =3D ccb->ccb_dma_handle; sata_cmd.addr_low =3D lower_32_bits(phys_addr); sata_cmd.addr_high =3D upper_32_bits(phys_addr); - sata_cmd.esgl =3D cpu_to_le32(1 << 31); + sata_cmd.esgl =3D cpu_to_le32(1U << 31); } else if (task->num_scatter =3D=3D 1) { u64 dma_addr =3D sg_dma_address(task->scatter); + sata_cmd.addr_low =3D lower_32_bits(dma_addr); sata_cmd.addr_high =3D upper_32_bits(dma_addr); sata_cmd.len =3D cpu_to_le32(task->total_xfer_len); sata_cmd.esgl =3D 0; + /* Check 4G Boundary */ - start_addr =3D cpu_to_le64(dma_addr); - end_addr =3D (start_addr + sata_cmd.len) - 1; - end_addr_low =3D cpu_to_le32(lower_32_bits(end_addr)); - end_addr_high =3D cpu_to_le32(upper_32_bits(end_addr)); + end_addr =3D dma_addr + le32_to_cpu(sata_cmd.len) - 1; + end_addr_low =3D lower_32_bits(end_addr); + end_addr_high =3D upper_32_bits(end_addr); if (end_addr_high !=3D sata_cmd.addr_high) { pm8001_dbg(pm8001_ha, FAIL, "The sg list address start_addr=3D0x%016llx data_len=3D0x%xend_add= r_high=3D0x%08x end_addr_low=3D0x%08x has crossed 4G boundary\n", - start_addr, sata_cmd.len, + dma_addr, + le32_to_cpu(sata_cmd.len), end_addr_high, end_addr_low); pm8001_chip_make_sg(task->scatter, 1, ccb->buf_prd); phys_addr =3D ccb->ccb_dma_handle; - sata_cmd.addr_low =3D - lower_32_bits(phys_addr); - sata_cmd.addr_high =3D - upper_32_bits(phys_addr); - sata_cmd.esgl =3D cpu_to_le32(1 << 31); + sata_cmd.addr_low =3D lower_32_bits(phys_addr); + sata_cmd.addr_high =3D upper_32_bits(phys_addr); + sata_cmd.esgl =3D cpu_to_le32(1U << 31); } } else if (task->num_scatter =3D=3D 0) { sata_cmd.addr_low =3D 0; @@ -4693,27 +4711,28 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_i= nfo *pm8001_ha, sata_cmd.len =3D cpu_to_le32(task->total_xfer_len); sata_cmd.esgl =3D 0; } + /* scsi cdb */ sata_cmd.atapi_scsi_cdb[0] =3D cpu_to_le32(((task->ata_task.atapi_packet[0]) | - (task->ata_task.atapi_packet[1] << 8) | - (task->ata_task.atapi_packet[2] << 16) | - (task->ata_task.atapi_packet[3] << 24))); + (task->ata_task.atapi_packet[1] << 8) | + (task->ata_task.atapi_packet[2] << 16) | + (task->ata_task.atapi_packet[3] << 24))); sata_cmd.atapi_scsi_cdb[1] =3D cpu_to_le32(((task->ata_task.atapi_packet[4]) | - (task->ata_task.atapi_packet[5] << 8) | - (task->ata_task.atapi_packet[6] << 16) | - (task->ata_task.atapi_packet[7] << 24))); + (task->ata_task.atapi_packet[5] << 8) | + (task->ata_task.atapi_packet[6] << 16) | + (task->ata_task.atapi_packet[7] << 24))); sata_cmd.atapi_scsi_cdb[2] =3D cpu_to_le32(((task->ata_task.atapi_packet[8]) | - (task->ata_task.atapi_packet[9] << 8) | - (task->ata_task.atapi_packet[10] << 16) | - (task->ata_task.atapi_packet[11] << 24))); + (task->ata_task.atapi_packet[9] << 8) | + (task->ata_task.atapi_packet[10] << 16) | + (task->ata_task.atapi_packet[11] << 24))); sata_cmd.atapi_scsi_cdb[3] =3D cpu_to_le32(((task->ata_task.atapi_packet[12]) | - (task->ata_task.atapi_packet[13] << 8) | - (task->ata_task.atapi_packet[14] << 16) | - (task->ata_task.atapi_packet[15] << 24))); + (task->ata_task.atapi_packet[13] << 8) | + (task->ata_task.atapi_packet[14] << 16) | + (task->ata_task.atapi_packet[15] << 24))); } =20 /* Check for read log for failed drive and return */ diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_att= r.c index 032efb294ee5..42e7298be521 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -555,7 +555,7 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobjec= t *kobj, if (!capable(CAP_SYS_ADMIN)) return -EINVAL; =20 - if (IS_NOCACHE_VPD_TYPE(ha)) + if (!IS_NOCACHE_VPD_TYPE(ha)) goto skip; =20 faddr =3D ha->flt_region_vpd << 2; @@ -745,7 +745,7 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kob= ject *kobj, ql_log(ql_log_info, vha, 0x706f, "Issuing MPI reset.\n"); =20 - if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + if (IS_QLA83XX(ha)) { uint32_t idc_control; =20 qla83xx_idc_lock(vha, 0); @@ -1056,9 +1056,6 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *vha, bool st= op_beacon) continue; if (iter->type =3D=3D 3 && !(IS_CNA_CAPABLE(ha))) continue; - if (iter->type =3D=3D 0x27 && - (!IS_QLA27XX(ha) || !IS_QLA28XX(ha))) - continue; =20 sysfs_remove_bin_file(&host->shost_gendev.kobj, iter->attr); diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 9da8034ccad4..c2f00f076f79 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -29,7 +29,8 @@ void qla2x00_bsg_job_done(srb_t *sp, int res) "%s: sp hdl %x, result=3D%x bsg ptr %p\n", __func__, sp->handle, res, bsg_job); =20 - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); =20 bsg_reply->result =3D res; bsg_job_done(bsg_job, bsg_reply->result, @@ -3013,7 +3014,8 @@ qla24xx_bsg_timeout(struct bsg_job *bsg_job) =20 done: spin_unlock_irqrestore(&ha->hardware_lock, flags); - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); return 0; } =20 diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 9ebf4a234d9a..aefb29d7c7ae 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -726,6 +726,11 @@ typedef struct srb { * code. */ void (*put_fn)(struct kref *kref); + + /* + * Report completion for asynchronous commands. + */ + void (*async_done)(struct srb *sp, int res); } srb_t; =20 #define GET_CMD_SP(sp) (sp->u.scmd.cmd) @@ -2886,7 +2891,11 @@ struct ct_fdmi2_hba_attributes { #define FDMI_PORT_SPEED_8GB 0x10 #define FDMI_PORT_SPEED_16GB 0x20 #define FDMI_PORT_SPEED_32GB 0x40 -#define FDMI_PORT_SPEED_64GB 0x80 +#define FDMI_PORT_SPEED_20GB 0x80 +#define FDMI_PORT_SPEED_40GB 0x100 +#define FDMI_PORT_SPEED_128GB 0x200 +#define FDMI_PORT_SPEED_64GB 0x400 +#define FDMI_PORT_SPEED_256GB 0x800 #define FDMI_PORT_SPEED_UNKNOWN 0x8000 =20 #define FC_CLASS_2 0x04 @@ -4262,8 +4271,10 @@ struct qla_hw_data { #define QLA_ABTS_WAIT_ENABLED(_sp) \ (QLA_NVME_IOS(_sp) && QLA_ABTS_FW_ENABLED(_sp->fcport->vha->hw)) =20 -#define IS_PI_UNINIT_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha)) -#define IS_PI_IPGUARD_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha)) +#define IS_PI_UNINIT_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \ + IS_QLA28XX(ha)) +#define IS_PI_IPGUARD_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \ + IS_QLA28XX(ha)) #define IS_PI_DIFB_DIX0_CAPABLE(ha) (0) #define IS_PI_SPLIT_DET_CAPABLE_HBA(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) = || \ IS_QLA28XX(ha)) @@ -4610,6 +4621,7 @@ struct qla_hw_data { struct workqueue_struct *wq; struct work_struct heartbeat_work; struct qlfc_fw fw_buf; + unsigned long last_heartbeat_run_jiffies; =20 /* FCP_CMND priority support */ struct qla_fcp_prio_cfg *fcp_prio_cfg; @@ -5427,4 +5439,8 @@ struct ql_vnd_tgt_stats_resp { #include "qla_gbl.h" #include "qla_dbg.h" #include "qla_inline.h" + +#define IS_SESSION_DELETED(_fcport) (_fcport->disc_state =3D=3D DSC_DELETE= _PEND || \ + _fcport->disc_state =3D=3D DSC_DELETED) + #endif diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edi= f.c index 53d2b8562027..0628633c7c7e 100644 --- a/drivers/scsi/qla2xxx/qla_edif.c +++ b/drivers/scsi/qla2xxx/qla_edif.c @@ -668,6 +668,11 @@ qla_edif_app_authok(scsi_qla_host_t *vha, struct bsg_j= ob *bsg_job) bsg_job->request_payload.sg_cnt, &appplogiok, sizeof(struct auth_complete_cmd)); =20 + /* silent unaligned access warning */ + portid.b.domain =3D appplogiok.u.d_id.b.domain; + portid.b.area =3D appplogiok.u.d_id.b.area; + portid.b.al_pa =3D appplogiok.u.d_id.b.al_pa; + switch (appplogiok.type) { case PL_TYPE_WWPN: fcport =3D qla2x00_find_fcport_by_wwpn(vha, @@ -678,7 +683,7 @@ qla_edif_app_authok(scsi_qla_host_t *vha, struct bsg_jo= b *bsg_job) __func__, appplogiok.u.wwpn); break; case PL_TYPE_DID: - fcport =3D qla2x00_find_fcport_by_pid(vha, &appplogiok.u.d_id); + fcport =3D qla2x00_find_fcport_by_pid(vha, &portid); if (!fcport) ql_dbg(ql_dbg_edif, vha, 0x911d, "%s d_id lookup failed: %x\n", __func__, @@ -777,6 +782,11 @@ qla_edif_app_authfail(scsi_qla_host_t *vha, struct bsg= _job *bsg_job) bsg_job->request_payload.sg_cnt, &appplogifail, sizeof(struct auth_complete_cmd)); =20 + /* silent unaligned access warning */ + portid.b.domain =3D appplogifail.u.d_id.b.domain; + portid.b.area =3D appplogifail.u.d_id.b.area; + portid.b.al_pa =3D appplogifail.u.d_id.b.al_pa; + /* * TODO: edif: app has failed this plogi. Inform driver to * take any action (if any). @@ -788,7 +798,7 @@ qla_edif_app_authfail(scsi_qla_host_t *vha, struct bsg_= job *bsg_job) SET_DID_STATUS(bsg_reply->result, DID_OK); break; case PL_TYPE_DID: - fcport =3D qla2x00_find_fcport_by_pid(vha, &appplogifail.u.d_id); + fcport =3D qla2x00_find_fcport_by_pid(vha, &portid); if (!fcport) ql_dbg(ql_dbg_edif, vha, 0x911d, "%s d_id lookup failed: %x\n", __func__, @@ -1253,6 +1263,7 @@ qla24xx_sadb_update(struct bsg_job *bsg_job) int result =3D 0; struct qla_sa_update_frame sa_frame; struct srb_iocb *iocb_cmd; + port_id_t portid; =20 ql_dbg(ql_dbg_edif + ql_dbg_verbose, vha, 0x911d, "%s entered, vha: 0x%p\n", __func__, vha); @@ -1276,7 +1287,12 @@ qla24xx_sadb_update(struct bsg_job *bsg_job) goto done; } =20 - fcport =3D qla2x00_find_fcport_by_pid(vha, &sa_frame.port_id); + /* silent unaligned access warning */ + portid.b.domain =3D sa_frame.port_id.b.domain; + portid.b.area =3D sa_frame.port_id.b.area; + portid.b.al_pa =3D sa_frame.port_id.b.al_pa; + + fcport =3D qla2x00_find_fcport_by_pid(vha, &portid); if (fcport) { found =3D 1; if (sa_frame.flags =3D=3D QLA_SA_UPDATE_FLAGS_TX_KEY) @@ -2146,7 +2162,8 @@ edif_doorbell_show(struct device *dev, struct device_= attribute *attr, =20 static void qla_noop_sp_done(srb_t *sp, int res) { - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); } =20 /* diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 8d8503a28479..3f8b8bbabe6d 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -316,7 +316,8 @@ extern int qla2x00_start_sp(srb_t *); extern int qla24xx_dif_start_scsi(srb_t *); extern int qla2x00_start_bidir(srb_t *, struct scsi_qla_host *, uint32_t); extern int qla2xxx_dif_start_scsi_mq(srb_t *); -extern void qla2x00_init_timer(srb_t *sp, unsigned long tmo); +extern void qla2x00_init_async_sp(srb_t *sp, unsigned long tmo, + void (*done)(struct srb *, int)); extern unsigned long qla2x00_get_async_timeout(struct scsi_qla_host *); =20 extern void *qla2x00_alloc_iocbs(struct scsi_qla_host *, srb_t *); @@ -332,6 +333,7 @@ extern int qla24xx_get_one_block_sg(uint32_t, struct ql= a2_sgx *, uint32_t *); extern int qla24xx_configure_prot_mode(srb_t *, uint16_t *); extern int qla24xx_issue_sa_replace_iocb(scsi_qla_host_t *vha, struct qla_work_evt *e); +void qla2x00_sp_release(struct kref *kref); =20 /* * Global Function Prototypes in qla_mbx.c source file. diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 28b574e20ef3..6b67bd561810 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -529,7 +529,6 @@ static void qla2x00_async_sns_sp_done(srb_t *sp, int rc) if (!e) goto err2; =20 - del_timer(&sp->u.iocb_cmd.timer); e->u.iosb.sp =3D sp; qla2x00_post_work(vha, e); return; @@ -556,8 +555,8 @@ static void qla2x00_async_sns_sp_done(srb_t *sp, int rc) sp->u.iocb_cmd.u.ctarg.rsp =3D NULL; } =20 - sp->free(sp); - + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); return; } =20 @@ -592,13 +591,15 @@ static int qla_async_rftid(scsi_qla_host_t *vha, port= _id_t *d_id) if (!vha->flags.online) goto done; =20 + /* ref: INIT */ sp =3D qla2x00_get_sp(vha, NULL, GFP_KERNEL); if (!sp) goto done; =20 sp->type =3D SRB_CT_PTHRU_CMD; sp->name =3D "rft_id"; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla2x00_async_sns_sp_done); =20 sp->u.iocb_cmd.u.ctarg.req =3D dma_alloc_coherent(&vha->hw->pdev->dev, sizeof(struct ct_sns_pkt), &sp->u.iocb_cmd.u.ctarg.req_dma, @@ -638,8 +639,6 @@ static int qla_async_rftid(scsi_qla_host_t *vha, port_i= d_t *d_id) sp->u.iocb_cmd.u.ctarg.req_size =3D RFT_ID_REQ_SIZE; sp->u.iocb_cmd.u.ctarg.rsp_size =3D RFT_ID_RSP_SIZE; sp->u.iocb_cmd.u.ctarg.nport_handle =3D NPH_SNS; - sp->u.iocb_cmd.timeout =3D qla2x00_async_iocb_timeout; - sp->done =3D qla2x00_async_sns_sp_done; =20 ql_dbg(ql_dbg_disc, vha, 0xffff, "Async-%s - hdl=3D%x portid %06x.\n", @@ -653,7 +652,8 @@ static int qla_async_rftid(scsi_qla_host_t *vha, port_i= d_t *d_id) } return rval; done_free_sp: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); done: return rval; } @@ -676,8 +676,7 @@ qla2x00_rff_id(scsi_qla_host_t *vha, u8 type) return (QLA_SUCCESS); } =20 - return qla_async_rffid(vha, &vha->d_id, qlt_rff_id(vha), - FC4_TYPE_FCP_SCSI); + return qla_async_rffid(vha, &vha->d_id, qlt_rff_id(vha), type); } =20 static int qla_async_rffid(scsi_qla_host_t *vha, port_id_t *d_id, @@ -688,13 +687,15 @@ static int qla_async_rffid(scsi_qla_host_t *vha, port= _id_t *d_id, srb_t *sp; struct ct_sns_pkt *ct_sns; =20 + /* ref: INIT */ sp =3D qla2x00_get_sp(vha, NULL, GFP_KERNEL); if (!sp) goto done; =20 sp->type =3D SRB_CT_PTHRU_CMD; sp->name =3D "rff_id"; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla2x00_async_sns_sp_done); =20 sp->u.iocb_cmd.u.ctarg.req =3D dma_alloc_coherent(&vha->hw->pdev->dev, sizeof(struct ct_sns_pkt), &sp->u.iocb_cmd.u.ctarg.req_dma, @@ -727,13 +728,11 @@ static int qla_async_rffid(scsi_qla_host_t *vha, port= _id_t *d_id, /* Prepare CT arguments -- port_id, FC-4 feature, FC-4 type */ ct_req->req.rff_id.port_id =3D port_id_to_be_id(*d_id); ct_req->req.rff_id.fc4_feature =3D fc4feature; - ct_req->req.rff_id.fc4_type =3D fc4type; /* SCSI - FCP */ + ct_req->req.rff_id.fc4_type =3D fc4type; /* SCSI-FCP or FC-NVMe */ =20 sp->u.iocb_cmd.u.ctarg.req_size =3D RFF_ID_REQ_SIZE; sp->u.iocb_cmd.u.ctarg.rsp_size =3D RFF_ID_RSP_SIZE; sp->u.iocb_cmd.u.ctarg.nport_handle =3D NPH_SNS; - sp->u.iocb_cmd.timeout =3D qla2x00_async_iocb_timeout; - sp->done =3D qla2x00_async_sns_sp_done; =20 ql_dbg(ql_dbg_disc, vha, 0xffff, "Async-%s - hdl=3D%x portid %06x feature %x type %x.\n", @@ -749,7 +748,8 @@ static int qla_async_rffid(scsi_qla_host_t *vha, port_i= d_t *d_id, return rval; =20 done_free_sp: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); done: return rval; } @@ -779,13 +779,15 @@ static int qla_async_rnnid(scsi_qla_host_t *vha, port= _id_t *d_id, srb_t *sp; struct ct_sns_pkt *ct_sns; =20 + /* ref: INIT */ sp =3D qla2x00_get_sp(vha, NULL, GFP_KERNEL); if (!sp) goto done; =20 sp->type =3D SRB_CT_PTHRU_CMD; sp->name =3D "rnid"; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla2x00_async_sns_sp_done); =20 sp->u.iocb_cmd.u.ctarg.req =3D dma_alloc_coherent(&vha->hw->pdev->dev, sizeof(struct ct_sns_pkt), &sp->u.iocb_cmd.u.ctarg.req_dma, @@ -823,9 +825,6 @@ static int qla_async_rnnid(scsi_qla_host_t *vha, port_i= d_t *d_id, sp->u.iocb_cmd.u.ctarg.rsp_size =3D RNN_ID_RSP_SIZE; sp->u.iocb_cmd.u.ctarg.nport_handle =3D NPH_SNS; =20 - sp->u.iocb_cmd.timeout =3D qla2x00_async_iocb_timeout; - sp->done =3D qla2x00_async_sns_sp_done; - ql_dbg(ql_dbg_disc, vha, 0xffff, "Async-%s - hdl=3D%x portid %06x\n", sp->name, sp->handle, d_id->b24); @@ -840,7 +839,8 @@ static int qla_async_rnnid(scsi_qla_host_t *vha, port_i= d_t *d_id, return rval; =20 done_free_sp: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); done: return rval; } @@ -886,13 +886,15 @@ static int qla_async_rsnn_nn(scsi_qla_host_t *vha) srb_t *sp; struct ct_sns_pkt *ct_sns; =20 + /* ref: INIT */ sp =3D qla2x00_get_sp(vha, NULL, GFP_KERNEL); if (!sp) goto done; =20 sp->type =3D SRB_CT_PTHRU_CMD; sp->name =3D "rsnn_nn"; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla2x00_async_sns_sp_done); =20 sp->u.iocb_cmd.u.ctarg.req =3D dma_alloc_coherent(&vha->hw->pdev->dev, sizeof(struct ct_sns_pkt), &sp->u.iocb_cmd.u.ctarg.req_dma, @@ -936,9 +938,6 @@ static int qla_async_rsnn_nn(scsi_qla_host_t *vha) sp->u.iocb_cmd.u.ctarg.rsp_size =3D RSNN_NN_RSP_SIZE; sp->u.iocb_cmd.u.ctarg.nport_handle =3D NPH_SNS; =20 - sp->u.iocb_cmd.timeout =3D qla2x00_async_iocb_timeout; - sp->done =3D qla2x00_async_sns_sp_done; - ql_dbg(ql_dbg_disc, vha, 0xffff, "Async-%s - hdl=3D%x.\n", sp->name, sp->handle); @@ -953,7 +952,8 @@ static int qla_async_rsnn_nn(scsi_qla_host_t *vha) return rval; =20 done_free_sp: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); done: return rval; } @@ -2893,7 +2893,8 @@ static void qla24xx_async_gpsc_sp_done(srb_t *sp, int= res) qla24xx_handle_gpsc_event(vha, &ea); =20 done: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); } =20 int qla24xx_async_gpsc(scsi_qla_host_t *vha, fc_port_t *fcport) @@ -2905,6 +2906,7 @@ int qla24xx_async_gpsc(scsi_qla_host_t *vha, fc_port_= t *fcport) if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT)) return rval; =20 + /* ref: INIT */ sp =3D qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) goto done; @@ -2913,8 +2915,8 @@ int qla24xx_async_gpsc(scsi_qla_host_t *vha, fc_port_= t *fcport) sp->name =3D "gpsc"; sp->gen1 =3D fcport->rscn_gen; sp->gen2 =3D fcport->login_gen; - - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla24xx_async_gpsc_sp_done); =20 /* CT_IU preamble */ ct_req =3D qla24xx_prep_ct_fm_req(fcport->ct_desc.ct_sns, GPSC_CMD, @@ -2932,9 +2934,6 @@ int qla24xx_async_gpsc(scsi_qla_host_t *vha, fc_port_= t *fcport) sp->u.iocb_cmd.u.ctarg.rsp_size =3D GPSC_RSP_SIZE; sp->u.iocb_cmd.u.ctarg.nport_handle =3D vha->mgmt_svr_loop_id; =20 - sp->u.iocb_cmd.timeout =3D qla2x00_async_iocb_timeout; - sp->done =3D qla24xx_async_gpsc_sp_done; - ql_dbg(ql_dbg_disc, vha, 0x205e, "Async-%s %8phC hdl=3D%x loopid=3D%x portid=3D%02x%02x%02x.\n", sp->name, fcport->port_name, sp->handle, @@ -2947,7 +2946,8 @@ int qla24xx_async_gpsc(scsi_qla_host_t *vha, fc_port_= t *fcport) return rval; =20 done_free_sp: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); done: return rval; } @@ -2996,7 +2996,8 @@ void qla24xx_sp_unmap(scsi_qla_host_t *vha, srb_t *sp) break; } =20 - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); } =20 void qla24xx_handle_gpnid_event(scsi_qla_host_t *vha, struct event_arg *ea) @@ -3135,13 +3136,15 @@ static void qla2x00_async_gpnid_sp_done(srb_t *sp, = int res) if (res) { if (res =3D=3D QLA_FUNCTION_TIMEOUT) { qla24xx_post_gpnid_work(sp->vha, &ea.id); - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); return; } } else if (sp->gen1) { /* There was another RSCN for this Nport ID */ qla24xx_post_gpnid_work(sp->vha, &ea.id); - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); return; } =20 @@ -3162,7 +3165,8 @@ static void qla2x00_async_gpnid_sp_done(srb_t *sp, in= t res) sp->u.iocb_cmd.u.ctarg.rsp_dma); sp->u.iocb_cmd.u.ctarg.rsp =3D NULL; =20 - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); return; } =20 @@ -3182,6 +3186,7 @@ int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_id= _t *id) if (!vha->flags.online) goto done; =20 + /* ref: INIT */ sp =3D qla2x00_get_sp(vha, NULL, GFP_KERNEL); if (!sp) goto done; @@ -3190,14 +3195,16 @@ int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_= id_t *id) sp->name =3D "gpnid"; sp->u.iocb_cmd.u.ctarg.id =3D *id; sp->gen1 =3D 0; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla2x00_async_gpnid_sp_done); =20 spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); list_for_each_entry(tsp, &vha->gpnid_list, elem) { if (tsp->u.iocb_cmd.u.ctarg.id.b24 =3D=3D id->b24) { tsp->gen1++; spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); goto done; } } @@ -3238,9 +3245,6 @@ int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_id= _t *id) sp->u.iocb_cmd.u.ctarg.rsp_size =3D GPN_ID_RSP_SIZE; sp->u.iocb_cmd.u.ctarg.nport_handle =3D NPH_SNS; =20 - sp->u.iocb_cmd.timeout =3D qla2x00_async_iocb_timeout; - sp->done =3D qla2x00_async_gpnid_sp_done; - ql_dbg(ql_dbg_disc, vha, 0x2067, "Async-%s hdl=3D%x ID %3phC.\n", sp->name, sp->handle, &ct_req->req.port_id.port_id); @@ -3270,8 +3274,8 @@ int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_id= _t *id) sp->u.iocb_cmd.u.ctarg.rsp_dma); sp->u.iocb_cmd.u.ctarg.rsp =3D NULL; } - - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); done: return rval; } @@ -3326,7 +3330,8 @@ void qla24xx_async_gffid_sp_done(srb_t *sp, int res) ea.rc =3D res; =20 qla24xx_handle_gffid_event(vha, &ea); - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); } =20 /* Get FC4 Feature with Nport ID. */ @@ -3339,6 +3344,7 @@ int qla24xx_async_gffid(scsi_qla_host_t *vha, fc_port= _t *fcport) if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT)) return rval; =20 + /* ref: INIT */ sp =3D qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) return rval; @@ -3348,9 +3354,8 @@ int qla24xx_async_gffid(scsi_qla_host_t *vha, fc_port= _t *fcport) sp->name =3D "gffid"; sp->gen1 =3D fcport->rscn_gen; sp->gen2 =3D fcport->login_gen; - - sp->u.iocb_cmd.timeout =3D qla2x00_async_iocb_timeout; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla24xx_async_gffid_sp_done); =20 /* CT_IU preamble */ ct_req =3D qla2x00_prep_ct_req(fcport->ct_desc.ct_sns, GFF_ID_CMD, @@ -3368,8 +3373,6 @@ int qla24xx_async_gffid(scsi_qla_host_t *vha, fc_port= _t *fcport) sp->u.iocb_cmd.u.ctarg.rsp_size =3D GFF_ID_RSP_SIZE; sp->u.iocb_cmd.u.ctarg.nport_handle =3D NPH_SNS; =20 - sp->done =3D qla24xx_async_gffid_sp_done; - ql_dbg(ql_dbg_disc, vha, 0x2132, "Async-%s hdl=3D%x %8phC.\n", sp->name, sp->handle, fcport->port_name); @@ -3380,7 +3383,8 @@ int qla24xx_async_gffid(scsi_qla_host_t *vha, fc_port= _t *fcport) =20 return rval; done_free_sp: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); fcport->flags &=3D ~FCF_ASYNC_SENT; return rval; } @@ -3767,7 +3771,6 @@ static void qla2x00_async_gpnft_gnnft_sp_done(srb_t *= sp, int res) "Async done-%s res %x FC4Type %x\n", sp->name, res, sp->gen2); =20 - del_timer(&sp->u.iocb_cmd.timer); sp->rc =3D res; if (res) { unsigned long flags; @@ -3892,9 +3895,8 @@ static int qla24xx_async_gnnft(scsi_qla_host_t *vha, = struct srb *sp, sp->name =3D "gnnft"; sp->gen1 =3D vha->hw->base_qpair->chip_reset; sp->gen2 =3D fc4_type; - - sp->u.iocb_cmd.timeout =3D qla2x00_async_iocb_timeout; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla2x00_async_gpnft_gnnft_sp_done); =20 memset(sp->u.iocb_cmd.u.ctarg.rsp, 0, sp->u.iocb_cmd.u.ctarg.rsp_size); memset(sp->u.iocb_cmd.u.ctarg.req, 0, sp->u.iocb_cmd.u.ctarg.req_size); @@ -3910,8 +3912,6 @@ static int qla24xx_async_gnnft(scsi_qla_host_t *vha, = struct srb *sp, sp->u.iocb_cmd.u.ctarg.req_size =3D GNN_FT_REQ_SIZE; sp->u.iocb_cmd.u.ctarg.nport_handle =3D NPH_SNS; =20 - sp->done =3D qla2x00_async_gpnft_gnnft_sp_done; - ql_dbg(ql_dbg_disc, vha, 0xffff, "Async-%s hdl=3D%x FC4Type %x.\n", sp->name, sp->handle, ct_req->req.gpn_ft.port_type); @@ -3938,8 +3938,8 @@ static int qla24xx_async_gnnft(scsi_qla_host_t *vha, = struct srb *sp, sp->u.iocb_cmd.u.ctarg.rsp_dma); sp->u.iocb_cmd.u.ctarg.rsp =3D NULL; } - - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); =20 spin_lock_irqsave(&vha->work_lock, flags); vha->scan.scan_flags &=3D ~SF_SCANNING; @@ -3991,9 +3991,12 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4= _type, srb_t *sp) ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff, "%s: Performing FCP Scan\n", __func__); =20 - if (sp) - sp->free(sp); /* should not happen */ + if (sp) { + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); + } =20 + /* ref: INIT */ sp =3D qla2x00_get_sp(vha, NULL, GFP_KERNEL); if (!sp) { spin_lock_irqsave(&vha->work_lock, flags); @@ -4038,6 +4041,7 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_= type, srb_t *sp) sp->u.iocb_cmd.u.ctarg.req, sp->u.iocb_cmd.u.ctarg.req_dma); sp->u.iocb_cmd.u.ctarg.req =3D NULL; + /* ref: INIT */ qla2x00_rel_sp(sp); return rval; } @@ -4057,9 +4061,8 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_= type, srb_t *sp) sp->name =3D "gpnft"; sp->gen1 =3D vha->hw->base_qpair->chip_reset; sp->gen2 =3D fc4_type; - - sp->u.iocb_cmd.timeout =3D qla2x00_async_iocb_timeout; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla2x00_async_gpnft_gnnft_sp_done); =20 rspsz =3D sp->u.iocb_cmd.u.ctarg.rsp_size; memset(sp->u.iocb_cmd.u.ctarg.rsp, 0, sp->u.iocb_cmd.u.ctarg.rsp_size); @@ -4074,8 +4077,6 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_= type, srb_t *sp) =20 sp->u.iocb_cmd.u.ctarg.nport_handle =3D NPH_SNS; =20 - sp->done =3D qla2x00_async_gpnft_gnnft_sp_done; - ql_dbg(ql_dbg_disc, vha, 0xffff, "Async-%s hdl=3D%x FC4Type %x.\n", sp->name, sp->handle, ct_req->req.gpn_ft.port_type); @@ -4103,7 +4104,8 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_= type, srb_t *sp) sp->u.iocb_cmd.u.ctarg.rsp =3D NULL; } =20 - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); =20 spin_lock_irqsave(&vha->work_lock, flags); vha->scan.scan_flags &=3D ~SF_SCANNING; @@ -4167,7 +4169,8 @@ static void qla2x00_async_gnnid_sp_done(srb_t *sp, in= t res) =20 qla24xx_handle_gnnid_event(vha, &ea); =20 - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); } =20 int qla24xx_async_gnnid(scsi_qla_host_t *vha, fc_port_t *fcport) @@ -4180,6 +4183,7 @@ int qla24xx_async_gnnid(scsi_qla_host_t *vha, fc_port= _t *fcport) return rval; =20 qla2x00_set_fcport_disc_state(fcport, DSC_GNN_ID); + /* ref: INIT */ sp =3D qla2x00_get_sp(vha, fcport, GFP_ATOMIC); if (!sp) goto done; @@ -4189,9 +4193,8 @@ int qla24xx_async_gnnid(scsi_qla_host_t *vha, fc_port= _t *fcport) sp->name =3D "gnnid"; sp->gen1 =3D fcport->rscn_gen; sp->gen2 =3D fcport->login_gen; - - sp->u.iocb_cmd.timeout =3D qla2x00_async_iocb_timeout; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla2x00_async_gnnid_sp_done); =20 /* CT_IU preamble */ ct_req =3D qla2x00_prep_ct_req(fcport->ct_desc.ct_sns, GNN_ID_CMD, @@ -4210,8 +4213,6 @@ int qla24xx_async_gnnid(scsi_qla_host_t *vha, fc_port= _t *fcport) sp->u.iocb_cmd.u.ctarg.rsp_size =3D GNN_ID_RSP_SIZE; sp->u.iocb_cmd.u.ctarg.nport_handle =3D NPH_SNS; =20 - sp->done =3D qla2x00_async_gnnid_sp_done; - ql_dbg(ql_dbg_disc, vha, 0xffff, "Async-%s - %8phC hdl=3D%x loopid=3D%x portid %06x.\n", sp->name, fcport->port_name, @@ -4223,7 +4224,8 @@ int qla24xx_async_gnnid(scsi_qla_host_t *vha, fc_port= _t *fcport) return rval; =20 done_free_sp: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); fcport->flags &=3D ~FCF_ASYNC_SENT; done: return rval; @@ -4297,7 +4299,8 @@ static void qla2x00_async_gfpnid_sp_done(srb_t *sp, i= nt res) =20 qla24xx_handle_gfpnid_event(vha, &ea); =20 - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); } =20 int qla24xx_async_gfpnid(scsi_qla_host_t *vha, fc_port_t *fcport) @@ -4309,6 +4312,7 @@ int qla24xx_async_gfpnid(scsi_qla_host_t *vha, fc_por= t_t *fcport) if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT)) return rval; =20 + /* ref: INIT */ sp =3D qla2x00_get_sp(vha, fcport, GFP_ATOMIC); if (!sp) goto done; @@ -4317,9 +4321,8 @@ int qla24xx_async_gfpnid(scsi_qla_host_t *vha, fc_por= t_t *fcport) sp->name =3D "gfpnid"; sp->gen1 =3D fcport->rscn_gen; sp->gen2 =3D fcport->login_gen; - - sp->u.iocb_cmd.timeout =3D qla2x00_async_iocb_timeout; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla2x00_async_gfpnid_sp_done); =20 /* CT_IU preamble */ ct_req =3D qla2x00_prep_ct_req(fcport->ct_desc.ct_sns, GFPN_ID_CMD, @@ -4338,8 +4341,6 @@ int qla24xx_async_gfpnid(scsi_qla_host_t *vha, fc_por= t_t *fcport) sp->u.iocb_cmd.u.ctarg.rsp_size =3D GFPN_ID_RSP_SIZE; sp->u.iocb_cmd.u.ctarg.nport_handle =3D NPH_SNS; =20 - sp->done =3D qla2x00_async_gfpnid_sp_done; - ql_dbg(ql_dbg_disc, vha, 0xffff, "Async-%s - %8phC hdl=3D%x loopid=3D%x portid %06x.\n", sp->name, fcport->port_name, @@ -4352,7 +4353,8 @@ int qla24xx_async_gfpnid(scsi_qla_host_t *vha, fc_por= t_t *fcport) return rval; =20 done_free_sp: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); done: return rval; } diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_ini= t.c index 070b636802d0..56ad42bb1742 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -51,6 +51,9 @@ qla2x00_sp_timeout(struct timer_list *t) WARN_ON(irqs_disabled()); iocb =3D &sp->u.iocb_cmd; iocb->timeout(sp); + + /* ref: TMR */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); } =20 void qla2x00_sp_free(srb_t *sp) @@ -125,8 +128,13 @@ static void qla24xx_abort_iocb_timeout(void *data) } spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); =20 - if (sp->cmd_sp) + if (sp->cmd_sp) { + /* + * This done function should take care of + * original command ref: INIT + */ sp->cmd_sp->done(sp->cmd_sp, QLA_OS_TIMER_EXPIRED); + } =20 abt->u.abt.comp_status =3D cpu_to_le16(CS_TIMEOUT); sp->done(sp, QLA_OS_TIMER_EXPIRED); @@ -140,11 +148,11 @@ static void qla24xx_abort_sp_done(srb_t *sp, int res) if (orig_sp) qla_wait_nvme_release_cmd_kref(orig_sp); =20 - del_timer(&sp->u.iocb_cmd.timer); if (sp->flags & SRB_WAKEUP_ON_COMP) complete(&abt->u.abt.comp); else - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); } =20 int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) @@ -154,6 +162,7 @@ int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) srb_t *sp; int rval =3D QLA_FUNCTION_FAILED; =20 + /* ref: INIT for ABTS command */ sp =3D qla2xxx_get_qpair_sp(cmd_sp->vha, cmd_sp->qpair, cmd_sp->fcport, GFP_ATOMIC); if (!sp) @@ -167,23 +176,22 @@ int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) if (wait) sp->flags =3D SRB_WAKEUP_ON_COMP; =20 - abt_iocb->timeout =3D qla24xx_abort_iocb_timeout; init_completion(&abt_iocb->u.abt.comp); /* FW can send 2 x ABTS's timeout/20s */ - qla2x00_init_timer(sp, 42); + qla2x00_init_async_sp(sp, 42, qla24xx_abort_sp_done); + sp->u.iocb_cmd.timeout =3D qla24xx_abort_iocb_timeout; =20 abt_iocb->u.abt.cmd_hndl =3D cmd_sp->handle; abt_iocb->u.abt.req_que_no =3D cpu_to_le16(cmd_sp->qpair->req->id); =20 - sp->done =3D qla24xx_abort_sp_done; - ql_dbg(ql_dbg_async, vha, 0x507c, "Abort command issued - hdl=3D%x, type=3D%x\n", cmd_sp->handle, cmd_sp->type); =20 rval =3D qla2x00_start_sp(sp); if (rval !=3D QLA_SUCCESS) { - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); return rval; } =20 @@ -191,7 +199,8 @@ int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) wait_for_completion(&abt_iocb->u.abt.comp); rval =3D abt_iocb->u.abt.comp_status =3D=3D CS_COMPLETE ? QLA_SUCCESS : QLA_ERR_FROM_FW; - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); } =20 return rval; @@ -286,10 +295,13 @@ static void qla2x00_async_login_sp_done(srb_t *sp, in= t res) ea.iop[0] =3D lio->u.logio.iop[0]; ea.iop[1] =3D lio->u.logio.iop[1]; ea.sp =3D sp; + if (res) + ea.data[0] =3D MBS_COMMAND_ERROR; qla24xx_handle_plogi_done_event(vha, &ea); } =20 - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); } =20 int @@ -308,6 +320,7 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_= t *fcport, return rval; } =20 + /* ref: INIT */ sp =3D qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) goto done; @@ -320,12 +333,10 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_por= t_t *fcport, sp->name =3D "login"; sp->gen1 =3D fcport->rscn_gen; sp->gen2 =3D fcport->login_gen; + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla2x00_async_login_sp_done); =20 lio =3D &sp->u.iocb_cmd; - lio->timeout =3D qla2x00_async_iocb_timeout; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); - - sp->done =3D qla2x00_async_login_sp_done; if (N2N_TOPO(fcport->vha->hw) && fcport_is_bigger(fcport)) { lio->u.logio.flags |=3D SRB_LOGIN_PRLI_ONLY; } else { @@ -358,7 +369,8 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_= t *fcport, return rval; =20 done_free_sp: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); fcport->flags &=3D ~FCF_ASYNC_SENT; done: fcport->flags &=3D ~FCF_ASYNC_ACTIVE; @@ -370,29 +382,26 @@ static void qla2x00_async_logout_sp_done(srb_t *sp, i= nt res) sp->fcport->flags &=3D ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); sp->fcport->login_gen++; qlt_logo_completion_handler(sp->fcport, sp->u.iocb_cmd.u.logio.data[0]); - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); } =20 int qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport) { srb_t *sp; - struct srb_iocb *lio; int rval =3D QLA_FUNCTION_FAILED; =20 fcport->flags |=3D FCF_ASYNC_SENT; + /* ref: INIT */ sp =3D qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) goto done; =20 sp->type =3D SRB_LOGOUT_CMD; sp->name =3D "logout"; - - lio =3D &sp->u.iocb_cmd; - lio->timeout =3D qla2x00_async_iocb_timeout; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); - - sp->done =3D qla2x00_async_logout_sp_done; + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla2x00_async_logout_sp_done), =20 ql_dbg(ql_dbg_disc, vha, 0x2070, "Async-logout - hdl=3D%x loop-id=3D%x portid=3D%02x%02x%02x %8phC exp= licit %d.\n", @@ -406,7 +415,8 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port= _t *fcport) return rval; =20 done_free_sp: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); done: fcport->flags &=3D ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); return rval; @@ -432,29 +442,26 @@ static void qla2x00_async_prlo_sp_done(srb_t *sp, int= res) if (!test_bit(UNLOADING, &vha->dpc_flags)) qla2x00_post_async_prlo_done_work(sp->fcport->vha, sp->fcport, lio->u.logio.data); - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); } =20 int qla2x00_async_prlo(struct scsi_qla_host *vha, fc_port_t *fcport) { srb_t *sp; - struct srb_iocb *lio; int rval; =20 rval =3D QLA_FUNCTION_FAILED; + /* ref: INIT */ sp =3D qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) goto done; =20 sp->type =3D SRB_PRLO_CMD; sp->name =3D "prlo"; - - lio =3D &sp->u.iocb_cmd; - lio->timeout =3D qla2x00_async_iocb_timeout; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); - - sp->done =3D qla2x00_async_prlo_sp_done; + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla2x00_async_prlo_sp_done); =20 ql_dbg(ql_dbg_disc, vha, 0x2070, "Async-prlo - hdl=3D%x loop-id=3D%x portid=3D%02x%02x%02x.\n", @@ -468,7 +475,8 @@ qla2x00_async_prlo(struct scsi_qla_host *vha, fc_port_t= *fcport) return rval; =20 done_free_sp: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); done: fcport->flags &=3D ~FCF_ASYNC_ACTIVE; return rval; @@ -551,10 +559,12 @@ static void qla2x00_async_adisc_sp_done(srb_t *sp, in= t res) ea.iop[1] =3D lio->u.logio.iop[1]; ea.fcport =3D sp->fcport; ea.sp =3D sp; + if (res) + ea.data[0] =3D MBS_COMMAND_ERROR; =20 qla24xx_handle_adisc_event(vha, &ea); - - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); } =20 int @@ -565,26 +575,34 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_por= t_t *fcport, struct srb_iocb *lio; int rval =3D QLA_FUNCTION_FAILED; =20 + if (IS_SESSION_DELETED(fcport)) { + ql_log(ql_log_warn, vha, 0xffff, + "%s: %8phC is being delete - not sending command.\n", + __func__, fcport->port_name); + fcport->flags &=3D ~FCF_ASYNC_ACTIVE; + return rval; + } + if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT)) return rval; =20 fcport->flags |=3D FCF_ASYNC_SENT; + /* ref: INIT */ sp =3D qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) goto done; =20 sp->type =3D SRB_ADISC_CMD; sp->name =3D "adisc"; - - lio =3D &sp->u.iocb_cmd; - lio->timeout =3D qla2x00_async_iocb_timeout; sp->gen1 =3D fcport->rscn_gen; sp->gen2 =3D fcport->login_gen; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla2x00_async_adisc_sp_done); =20 - sp->done =3D qla2x00_async_adisc_sp_done; - if (data[1] & QLA_LOGIO_LOGIN_RETRIED) + if (data[1] & QLA_LOGIO_LOGIN_RETRIED) { + lio =3D &sp->u.iocb_cmd; lio->u.logio.flags |=3D SRB_LOGIN_RETRIED; + } =20 ql_dbg(ql_dbg_disc, vha, 0x206f, "Async-adisc - hdl=3D%x loopid=3D%x portid=3D%06x %8phC.\n", @@ -597,7 +615,8 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_= t *fcport, return rval; =20 done_free_sp: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); done: fcport->flags &=3D ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); qla2x00_post_async_adisc_work(vha, fcport, data); @@ -963,6 +982,9 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host= _t *vha, set_bit(RELOGIN_NEEDED, &vha->dpc_flags); } break; + case ISP_CFG_NL: + qla24xx_fcport_handle_login(vha, fcport); + break; default: break; } @@ -1078,13 +1100,13 @@ static void qla24xx_async_gnl_sp_done(srb_t *sp, in= t res) } spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); =20 - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); } =20 int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport) { srb_t *sp; - struct srb_iocb *mbx; int rval =3D QLA_FUNCTION_FAILED; unsigned long flags; u16 *mb; @@ -1109,6 +1131,7 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_p= ort_t *fcport) vha->gnl.sent =3D 1; spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); =20 + /* ref: INIT */ sp =3D qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) goto done; @@ -1117,10 +1140,8 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_= port_t *fcport) sp->name =3D "gnlist"; sp->gen1 =3D fcport->rscn_gen; sp->gen2 =3D fcport->login_gen; - - mbx =3D &sp->u.iocb_cmd; - mbx->timeout =3D qla2x00_async_iocb_timeout; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha)+2); + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla24xx_async_gnl_sp_done); =20 mb =3D sp->u.iocb_cmd.u.mbx.out_mb; mb[0] =3D MBC_PORT_NODE_NAME_LIST; @@ -1132,8 +1153,6 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_p= ort_t *fcport) mb[8] =3D vha->gnl.size; mb[9] =3D vha->vp_idx; =20 - sp->done =3D qla24xx_async_gnl_sp_done; - ql_dbg(ql_dbg_disc, vha, 0x20da, "Async-%s - OUT WWPN %8phC hndl %x\n", sp->name, fcport->port_name, sp->handle); @@ -1145,7 +1164,8 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_p= ort_t *fcport) return rval; =20 done_free_sp: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); done: fcport->flags &=3D ~(FCF_ASYNC_ACTIVE | FCF_ASYNC_SENT); return rval; @@ -1191,7 +1211,7 @@ static void qla24xx_async_gpdb_sp_done(srb_t *sp, int= res) dma_pool_free(ha->s_dma_pool, sp->u.iocb_cmd.u.mbx.in, sp->u.iocb_cmd.u.mbx.in_dma); =20 - sp->free(sp); + kref_put(&sp->cmd_kref, qla2x00_sp_release); } =20 int qla24xx_post_prli_work(struct scsi_qla_host *vha, fc_port_t *fcport) @@ -1232,11 +1252,13 @@ static void qla2x00_async_prli_sp_done(srb_t *sp, i= nt res) ea.sp =3D sp; if (res =3D=3D QLA_OS_TIMER_EXPIRED) ea.data[0] =3D QLA_OS_TIMER_EXPIRED; + else if (res) + ea.data[0] =3D MBS_COMMAND_ERROR; =20 qla24xx_handle_prli_done_event(vha, &ea); } =20 - sp->free(sp); + kref_put(&sp->cmd_kref, qla2x00_sp_release); } =20 int @@ -1269,12 +1291,10 @@ qla24xx_async_prli(struct scsi_qla_host *vha, fc_po= rt_t *fcport) =20 sp->type =3D SRB_PRLI_CMD; sp->name =3D "prli"; + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla2x00_async_prli_sp_done); =20 lio =3D &sp->u.iocb_cmd; - lio->timeout =3D qla2x00_async_iocb_timeout; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); - - sp->done =3D qla2x00_async_prli_sp_done; lio->u.logio.flags =3D 0; =20 if (NVME_TARGET(vha->hw, fcport)) @@ -1296,7 +1316,8 @@ qla24xx_async_prli(struct scsi_qla_host *vha, fc_port= _t *fcport) return rval; =20 done_free_sp: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); fcport->flags &=3D ~FCF_ASYNC_SENT; return rval; } @@ -1325,14 +1346,21 @@ int qla24xx_async_gpdb(struct scsi_qla_host *vha, f= c_port_t *fcport, u8 opt) struct port_database_24xx *pd; struct qla_hw_data *ha =3D vha->hw; =20 - if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT) || - fcport->loop_id =3D=3D FC_NO_LOOP_ID) { + if (IS_SESSION_DELETED(fcport)) { ql_log(ql_log_warn, vha, 0xffff, - "%s: %8phC - not sending command.\n", - __func__, fcport->port_name); + "%s: %8phC is being delete - not sending command.\n", + __func__, fcport->port_name); + fcport->flags &=3D ~FCF_ASYNC_ACTIVE; return rval; } =20 + if (!vha->flags.online || fcport->flags & FCF_ASYNC_SENT) { + ql_log(ql_log_warn, vha, 0xffff, + "%s: %8phC online %d flags %x - not sending command.\n", + __func__, fcport->port_name, vha->flags.online, fcport->flags); + goto done; + } + sp =3D qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) goto done; @@ -1344,10 +1372,8 @@ int qla24xx_async_gpdb(struct scsi_qla_host *vha, fc= _port_t *fcport, u8 opt) sp->name =3D "gpdb"; sp->gen1 =3D fcport->rscn_gen; sp->gen2 =3D fcport->login_gen; - - mbx =3D &sp->u.iocb_cmd; - mbx->timeout =3D qla2x00_async_iocb_timeout; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla24xx_async_gpdb_sp_done); =20 pd =3D dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &pd_dma); if (pd =3D=3D NULL) { @@ -1366,11 +1392,10 @@ int qla24xx_async_gpdb(struct scsi_qla_host *vha, f= c_port_t *fcport, u8 opt) mb[9] =3D vha->vp_idx; mb[10] =3D opt; =20 - mbx->u.mbx.in =3D pd; + mbx =3D &sp->u.iocb_cmd; + mbx->u.mbx.in =3D (void *)pd; mbx->u.mbx.in_dma =3D pd_dma; =20 - sp->done =3D qla24xx_async_gpdb_sp_done; - ql_dbg(ql_dbg_disc, vha, 0x20dc, "Async-%s %8phC hndl %x opt %x\n", sp->name, fcport->port_name, sp->handle, opt); @@ -1384,7 +1409,7 @@ int qla24xx_async_gpdb(struct scsi_qla_host *vha, fc_= port_t *fcport, u8 opt) if (pd) dma_pool_free(ha->s_dma_pool, pd, pd_dma); =20 - sp->free(sp); + kref_put(&sp->cmd_kref, qla2x00_sp_release); fcport->flags &=3D ~FCF_ASYNC_SENT; done: fcport->flags &=3D ~FCF_ASYNC_ACTIVE; @@ -1556,6 +1581,11 @@ static void qla_chk_n2n_b4_login(struct scsi_qla_hos= t *vha, fc_port_t *fcport) u8 login =3D 0; int rc; =20 + ql_dbg(ql_dbg_disc, vha, 0x307b, + "%s %8phC DS %d LS %d lid %d retries=3D%d\n", + __func__, fcport->port_name, fcport->disc_state, + fcport->fw_login_state, fcport->loop_id, fcport->login_retry); + if (qla_tgt_mode_enabled(vha)) return; =20 @@ -1614,7 +1644,8 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host = *vha, fc_port_t *fcport) fcport->login_gen, fcport->loop_id, fcport->scan_state, fcport->fc4_type); =20 - if (fcport->scan_state !=3D QLA_FCPORT_FOUND) + if (fcport->scan_state !=3D QLA_FCPORT_FOUND || + fcport->disc_state =3D=3D DSC_DELETE_PEND) return 0; =20 if ((fcport->loop_id !=3D FC_NO_LOOP_ID) && @@ -1635,7 +1666,7 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host = *vha, fc_port_t *fcport) if (vha->host->active_mode =3D=3D MODE_TARGET && !N2N_TOPO(vha->hw)) return 0; =20 - if (fcport->flags & FCF_ASYNC_SENT) { + if (fcport->flags & (FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE)) { set_bit(RELOGIN_NEEDED, &vha->dpc_flags); return 0; } @@ -1970,22 +2001,21 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t fl= ags, uint32_t lun, srb_t *sp; int rval =3D QLA_FUNCTION_FAILED; =20 + /* ref: INIT */ sp =3D qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) goto done; =20 - tm_iocb =3D &sp->u.iocb_cmd; sp->type =3D SRB_TM_CMD; sp->name =3D "tmf"; + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha), + qla2x00_tmf_sp_done); + sp->u.iocb_cmd.timeout =3D qla2x00_tmf_iocb_timeout; =20 - tm_iocb->timeout =3D qla2x00_tmf_iocb_timeout; + tm_iocb =3D &sp->u.iocb_cmd; init_completion(&tm_iocb->u.tmf.comp); - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha)); - tm_iocb->u.tmf.flags =3D flags; tm_iocb->u.tmf.lun =3D lun; - tm_iocb->u.tmf.data =3D tag; - sp->done =3D qla2x00_tmf_sp_done; =20 ql_dbg(ql_dbg_taskm, vha, 0x802f, "Async-tmf hdl=3D%x loop-id=3D%x portid=3D%02x%02x%02x.\n", @@ -2015,7 +2045,8 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flag= s, uint32_t lun, } =20 done_free_sp: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); fcport->flags &=3D ~FCF_ASYNC_SENT; done: return rval; @@ -2074,13 +2105,6 @@ qla24xx_handle_prli_done_event(struct scsi_qla_host = *vha, struct event_arg *ea) qla24xx_post_gpdb_work(vha, ea->fcport, 0); break; default: - if ((ea->iop[0] =3D=3D LSC_SCODE_ELS_REJECT) && - (ea->iop[1] =3D=3D 0x50000)) { /* reson 5=3Dbusy expl:0x0 */ - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); - ea->fcport->fw_login_state =3D DSC_LS_PLOGI_COMP; - break; - } - sp =3D ea->sp; ql_dbg(ql_dbg_disc, vha, 0x2118, "%s %d %8phC priority %s, fc4type %x prev try %s\n", @@ -2224,12 +2248,7 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host= *vha, struct event_arg *ea) ql_dbg(ql_dbg_disc, vha, 0x20eb, "%s %d %8phC cmd error %x\n", __func__, __LINE__, ea->fcport->port_name, ea->data[1]); =20 - ea->fcport->flags &=3D ~FCF_ASYNC_SENT; - qla2x00_set_fcport_disc_state(ea->fcport, DSC_LOGIN_FAILED); - if (ea->data[1] & QLA_LOGIO_LOGIN_RETRIED) - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); - else - qla2x00_mark_device_lost(vha, ea->fcport, 1); + qlt_schedule_sess_for_deletion(ea->fcport); break; case MBS_LOOP_ID_USED: /* data[1] =3D IO PARAM 1 =3D nport ID */ @@ -3472,6 +3491,14 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) struct rsp_que *rsp =3D ha->rsp_q_map[0]; struct qla2xxx_fw_dump *fw_dump; =20 + if (ha->fw_dump) { + ql_dbg(ql_dbg_init, vha, 0x00bd, + "Firmware dump already allocated.\n"); + return; + } + + ha->fw_dumped =3D 0; + ha->fw_dump_cap_flags =3D 0; dump_size =3D fixed_size =3D mem_size =3D eft_size =3D fce_size =3D mq_si= ze =3D 0; req_q_size =3D rsp_q_size =3D 0; =20 @@ -3482,7 +3509,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) mem_size =3D (ha->fw_memory_size - 0x11000 + 1) * sizeof(uint16_t); } else if (IS_FWI2_CAPABLE(ha)) { - if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) + if (IS_QLA83XX(ha)) fixed_size =3D offsetof(struct qla83xx_fw_dump, ext_mem); else if (IS_QLA81XX(ha)) fixed_size =3D offsetof(struct qla81xx_fw_dump, ext_mem); @@ -3494,8 +3521,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) mem_size =3D (ha->fw_memory_size - 0x100000 + 1) * sizeof(uint32_t); if (ha->mqenable) { - if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && - !IS_QLA28XX(ha)) + if (!IS_QLA83XX(ha)) mq_size =3D sizeof(struct qla2xxx_mq_chain); /* * Allocate maximum buffer size for all queues - Q0. @@ -4056,8 +4082,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) ha->fw_major_version, ha->fw_minor_version, ha->fw_subminor_version); =20 - if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || - IS_QLA28XX(ha)) { + if (IS_QLA83XX(ha)) { ha->flags.fac_supported =3D 0; rval =3D QLA_SUCCESS; } @@ -5602,6 +5627,13 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) memcpy(fcport->node_name, new_fcport->node_name, WWN_SIZE); fcport->scan_state =3D QLA_FCPORT_FOUND; + if (fcport->login_retry =3D=3D 0) { + fcport->login_retry =3D vha->hw->login_retry_count; + ql_dbg(ql_dbg_disc, vha, 0x2135, + "Port login retry %8phN, lid 0x%04x retry cnt=3D%d.\n", + fcport->port_name, fcport->loop_id, + fcport->login_retry); + } found++; break; } @@ -5735,6 +5767,8 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port= _t *fcport) if (atomic_read(&fcport->state) =3D=3D FCS_ONLINE) return; =20 + qla2x00_set_fcport_state(fcport, FCS_ONLINE); + rport_ids.node_name =3D wwn_to_u64(fcport->node_name); rport_ids.port_name =3D wwn_to_u64(fcport->port_name); rport_ids.port_id =3D fcport->d_id.b.domain << 16 | @@ -5842,6 +5876,7 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t= *fcport) qla2x00_reg_remote_port(vha, fcport); break; case MODE_TARGET: + qla2x00_set_fcport_state(fcport, FCS_ONLINE); if (!vha->vha_tgt.qla_tgt->tgt_stop && !vha->vha_tgt.qla_tgt->tgt_stopped) qlt_fc_port_added(vha, fcport); @@ -5856,8 +5891,6 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t= *fcport) break; } =20 - qla2x00_set_fcport_state(fcport, FCS_ONLINE); - if (IS_IIDMA_CAPABLE(vha->hw) && vha->hw->flags.gpsc_supported) { if (fcport->id_changed) { fcport->id_changed =3D 0; @@ -9394,7 +9427,7 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_ql= a_host *vha, int qos, qpair->rsp->req =3D qpair->req; qpair->rsp->qpair =3D qpair; /* init qpair to this cpu. Will adjust at run time. */ - qla_cpu_update(qpair, smp_processor_id()); + qla_cpu_update(qpair, raw_smp_processor_id()); =20 if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) { if (ha->fw_attributes & BIT_4) diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_i= nline.h index 5f3b7995cc8f..db17f7f410cd 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -184,6 +184,8 @@ static void qla2xxx_init_sp(srb_t *sp, scsi_qla_host_t = *vha, sp->vha =3D vha; sp->qpair =3D qpair; sp->cmd_type =3D TYPE_SRB; + /* ref : INIT - normal flow */ + kref_init(&sp->cmd_kref); INIT_LIST_HEAD(&sp->elem); } =20 diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_ioc= b.c index ed604f2185bf..e0fe9ddb4bd2 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -2560,11 +2560,38 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *t= sk) } } =20 -void qla2x00_init_timer(srb_t *sp, unsigned long tmo) +static void +qla2x00_async_done(struct srb *sp, int res) +{ + if (del_timer(&sp->u.iocb_cmd.timer)) { + /* + * Successfully cancelled the timeout handler + * ref: TMR + */ + if (kref_put(&sp->cmd_kref, qla2x00_sp_release)) + return; + } + sp->async_done(sp, res); +} + +void +qla2x00_sp_release(struct kref *kref) +{ + struct srb *sp =3D container_of(kref, struct srb, cmd_kref); + + sp->free(sp); +} + +void +qla2x00_init_async_sp(srb_t *sp, unsigned long tmo, + void (*done)(struct srb *sp, int res)) { timer_setup(&sp->u.iocb_cmd.timer, qla2x00_sp_timeout, 0); - sp->u.iocb_cmd.timer.expires =3D jiffies + tmo * HZ; + sp->done =3D qla2x00_async_done; + sp->async_done =3D done; sp->free =3D qla2x00_sp_free; + sp->u.iocb_cmd.timeout =3D qla2x00_async_iocb_timeout; + sp->u.iocb_cmd.timer.expires =3D jiffies + tmo * HZ; if (IS_QLAFX00(sp->vha->hw) && sp->type =3D=3D SRB_FXIOCB_DCMD) init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp); sp->start_timer =3D 1; @@ -2651,7 +2678,9 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_o= pcode, return -ENOMEM; } =20 - /* Alloc SRB structure */ + /* Alloc SRB structure + * ref: INIT + */ sp =3D qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) { kfree(fcport); @@ -2672,18 +2701,19 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els= _opcode, sp->type =3D SRB_ELS_DCMD; sp->name =3D "ELS_DCMD"; sp->fcport =3D fcport; - elsio->timeout =3D qla2x00_els_dcmd_iocb_timeout; - qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT); - init_completion(&sp->u.iocb_cmd.u.els_logo.comp); - sp->done =3D qla2x00_els_dcmd_sp_done; + qla2x00_init_async_sp(sp, ELS_DCMD_TIMEOUT, + qla2x00_els_dcmd_sp_done); sp->free =3D qla2x00_els_dcmd_sp_free; + sp->u.iocb_cmd.timeout =3D qla2x00_els_dcmd_iocb_timeout; + init_completion(&sp->u.iocb_cmd.u.els_logo.comp); =20 elsio->u.els_logo.els_logo_pyld =3D dma_alloc_coherent(&ha->pdev->dev, DMA_POOL_SIZE, &elsio->u.els_logo.els_logo_pyld_dma, GFP_KERNEL); =20 if (!elsio->u.els_logo.els_logo_pyld) { - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); return QLA_FUNCTION_FAILED; } =20 @@ -2706,7 +2736,8 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_o= pcode, =20 rval =3D qla2x00_start_sp(sp); if (rval !=3D QLA_SUCCESS) { - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); return QLA_FUNCTION_FAILED; } =20 @@ -2717,7 +2748,8 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_o= pcode, =20 wait_for_completion(&elsio->u.els_logo.comp); =20 - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); return rval; } =20 @@ -2850,7 +2882,6 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int = res) sp->name, res, sp->handle, fcport->d_id.b24, fcport->port_name); =20 fcport->flags &=3D ~(FCF_ASYNC_SENT|FCF_ASYNC_ACTIVE); - del_timer(&sp->u.iocb_cmd.timer); =20 if (sp->flags & SRB_WAKEUP_ON_COMP) complete(&lio->u.els_plogi.comp); @@ -2927,6 +2958,7 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int = res) set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); + break; } fallthrough; default: @@ -2936,9 +2968,7 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int = res) fw_status[0], fw_status[1], fw_status[2]); =20 fcport->flags &=3D ~FCF_ASYNC_SENT; - qla2x00_set_fcport_disc_state(fcport, - DSC_LOGIN_FAILED); - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + qlt_schedule_sess_for_deletion(fcport); break; } break; @@ -2950,8 +2980,7 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int = res) fw_status[0], fw_status[1], fw_status[2]); =20 sp->fcport->flags &=3D ~FCF_ASYNC_SENT; - qla2x00_set_fcport_disc_state(fcport, DSC_LOGIN_FAILED); - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + qlt_schedule_sess_for_deletion(fcport); break; } =20 @@ -2960,7 +2989,8 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int = res) struct srb_iocb *elsio =3D &sp->u.iocb_cmd; =20 qla2x00_els_dcmd2_free(vha, &elsio->u.els_plogi); - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); return; } e->u.iosb.sp =3D sp; @@ -2978,7 +3008,9 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_= opcode, int rval =3D QLA_SUCCESS; void *ptr, *resp_ptr; =20 - /* Alloc SRB structure */ + /* Alloc SRB structure + * ref: INIT + */ sp =3D qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) { ql_log(ql_log_info, vha, 0x70e6, @@ -2993,17 +3025,16 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int el= s_opcode, ql_dbg(ql_dbg_io, vha, 0x3073, "%s Enter: PLOGI portid=3D%06x\n", __func__, fcport->d_id.b24); =20 - sp->type =3D SRB_ELS_DCMD; - sp->name =3D "ELS_DCMD"; - sp->fcport =3D fcport; - - elsio->timeout =3D qla2x00_els_dcmd2_iocb_timeout; if (wait) sp->flags =3D SRB_WAKEUP_ON_COMP; =20 - qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT + 2); + sp->type =3D SRB_ELS_DCMD; + sp->name =3D "ELS_DCMD"; + sp->fcport =3D fcport; + qla2x00_init_async_sp(sp, ELS_DCMD_TIMEOUT + 2, + qla2x00_els_dcmd2_sp_done); + sp->u.iocb_cmd.timeout =3D qla2x00_els_dcmd2_iocb_timeout; =20 - sp->done =3D qla2x00_els_dcmd2_sp_done; elsio->u.els_plogi.tx_size =3D elsio->u.els_plogi.rx_size =3D DMA_POOL_SI= ZE; =20 ptr =3D elsio->u.els_plogi.els_plogi_pyld =3D @@ -3068,7 +3099,8 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_= opcode, out: fcport->flags &=3D ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); qla2x00_els_dcmd2_free(vha, &elsio->u.els_plogi); - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); done: return rval; } @@ -3879,8 +3911,15 @@ qla2x00_start_sp(srb_t *sp) break; } =20 - if (sp->start_timer) + if (sp->start_timer) { + /* ref: TMR timer ref + * this code should be just before start_iocbs function + * This will make sure that caller function don't to do + * kref_put even on failure + */ + kref_get(&sp->cmd_kref); add_timer(&sp->u.iocb_cmd.timer); + } =20 wmb(); qla2x00_start_iocbs(vha, qp->req); diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index aaf6504570fd..198b782d7790 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2498,6 +2498,7 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct re= q_que *req, void *tsk) iocb->u.tmf.data =3D QLA_FUNCTION_FAILED; } else if ((le16_to_cpu(sts->scsi_status) & SS_RESPONSE_INFO_LEN_VALID)) { + host_to_fcp_swap(sts->data, sizeof(sts->data)); if (le32_to_cpu(sts->rsp_data_len) < 4) { ql_log(ql_log_warn, fcport->vha, 0x503b, "Async-%s error - hdl=3D%x not enough response(%d).\n", diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 10d2655ef676..7f236db05886 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -9,6 +9,12 @@ #include #include =20 +#ifdef CONFIG_PPC +#define IS_PPCARCH true +#else +#define IS_PPCARCH false +#endif + static struct mb_cmd_name { uint16_t cmd; const char *str; @@ -728,6 +734,9 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_= addr) vha->min_supported_speed =3D nv->min_supported_speed; } + + if (IS_PPCARCH) + mcp->mb[11] |=3D BIT_4; } =20 if (ha->flags.exlogins_enabled) @@ -3029,8 +3038,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha) ha->orig_fw_iocb_count =3D mcp->mb[10]; if (ha->flags.npiv_supported) ha->max_npiv_vports =3D mcp->mb[11]; - if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) || - IS_QLA28XX(ha)) + if (IS_QLA81XX(ha) || IS_QLA83XX(ha)) ha->fw_max_fcf_count =3D mcp->mb[12]; } =20 @@ -5621,7 +5629,7 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha) mcp->out_mb =3D MBX_1|MBX_0; mcp->in_mb =3D MBX_2|MBX_1|MBX_0; if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) - mcp->in_mb |=3D MBX_3; + mcp->in_mb |=3D MBX_4|MBX_3; mcp->tov =3D MBX_TOV_SECONDS; mcp->flags =3D 0; rval =3D qla2x00_mailbox_command(vha, mcp); @@ -6479,23 +6487,21 @@ int qla24xx_send_mb_cmd(struct scsi_qla_host *vha, = mbx_cmd_t *mcp) if (!vha->hw->flags.fw_started) goto done; =20 + /* ref: INIT */ sp =3D qla2x00_get_sp(vha, NULL, GFP_KERNEL); if (!sp) goto done; =20 - sp->type =3D SRB_MB_IOCB; - sp->name =3D mb_to_str(mcp->mb[0]); - c =3D &sp->u.iocb_cmd; - c->timeout =3D qla2x00_async_iocb_timeout; init_completion(&c->u.mbx.comp); =20 - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + sp->type =3D SRB_MB_IOCB; + sp->name =3D mb_to_str(mcp->mb[0]); + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla2x00_async_mb_sp_done); =20 memcpy(sp->u.iocb_cmd.u.mbx.out_mb, mcp->mb, SIZEOF_IOCB_MB_REG); =20 - sp->done =3D qla2x00_async_mb_sp_done; - rval =3D qla2x00_start_sp(sp); if (rval !=3D QLA_SUCCESS) { ql_dbg(ql_dbg_mbx, vha, 0x1018, @@ -6527,7 +6533,8 @@ int qla24xx_send_mb_cmd(struct scsi_qla_host *vha, mb= x_cmd_t *mcp) } =20 done_free_sp: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); done: return rval; } diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 1c024055f8c5..e6b5c4ccce97 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -965,6 +965,7 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd) if (vp_index =3D=3D 0 || vp_index >=3D ha->max_npiv_vports) return QLA_PARAMETER_ERROR; =20 + /* ref: INIT */ sp =3D qla2x00_get_sp(base_vha, NULL, GFP_KERNEL); if (!sp) return rval; @@ -972,9 +973,8 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd) sp->type =3D SRB_CTRL_VP; sp->name =3D "ctrl_vp"; sp->comp =3D ∁ - sp->done =3D qla_ctrlvp_sp_done; - sp->u.iocb_cmd.timeout =3D qla2x00_async_iocb_timeout; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla_ctrlvp_sp_done); sp->u.iocb_cmd.u.ctrlvp.cmd =3D cmd; sp->u.iocb_cmd.u.ctrlvp.vp_index =3D vp_index; =20 @@ -1008,6 +1008,7 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd) break; } done: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); return rval; } diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c index 350b0c4346fb..f726eb8449c5 100644 --- a/drivers/scsi/qla2xxx/qla_mr.c +++ b/drivers/scsi/qla2xxx/qla_mr.c @@ -1787,17 +1787,18 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fc= port, uint16_t fx_type) struct register_host_info *preg_hsi; struct new_utsname *p_sysid =3D NULL; =20 + /* ref: INIT */ sp =3D qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) goto done; =20 sp->type =3D SRB_FXIOCB_DCMD; sp->name =3D "fxdisc"; + qla2x00_init_async_sp(sp, FXDISC_TIMEOUT, + qla2x00_fxdisc_sp_done); + sp->u.iocb_cmd.timeout =3D qla2x00_fxdisc_iocb_timeout; =20 fdisc =3D &sp->u.iocb_cmd; - fdisc->timeout =3D qla2x00_fxdisc_iocb_timeout; - qla2x00_init_timer(sp, FXDISC_TIMEOUT); - switch (fx_type) { case FXDISC_GET_CONFIG_INFO: fdisc->u.fxiocb.flags =3D @@ -1898,7 +1899,6 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcpo= rt, uint16_t fx_type) } =20 fdisc->u.fxiocb.req_func_type =3D cpu_to_le16(fx_type); - sp->done =3D qla2x00_fxdisc_sp_done; =20 rval =3D qla2x00_start_sp(sp); if (rval !=3D QLA_SUCCESS) @@ -1974,7 +1974,8 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcpo= rt, uint16_t fx_type) dma_free_coherent(&ha->pdev->dev, fdisc->u.fxiocb.req_len, fdisc->u.fxiocb.req_addr, fdisc->u.fxiocb.req_dma_handle); done_free_sp: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); done: return rval; } diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvm= e.c index 138ffdb5c92c..fd4c1167b2ce 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -37,6 +37,11 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, = struct fc_port *fcport) (fcport->nvme_flag & NVME_FLAG_REGISTERED)) return 0; =20 + if (atomic_read(&fcport->state) =3D=3D FCS_ONLINE) + return 0; + + qla2x00_set_fcport_state(fcport, FCS_ONLINE); + fcport->nvme_flag &=3D ~NVME_FLAG_RESETTING; =20 memset(&req, 0, sizeof(struct nvme_fc_port_info)); @@ -167,6 +172,18 @@ static void qla_nvme_release_fcp_cmd_kref(struct kref = *kref) qla2xxx_rel_qpair_sp(sp->qpair, sp); } =20 +static void qla_nvme_ls_unmap(struct srb *sp, struct nvmefc_ls_req *fd) +{ + if (sp->flags & SRB_DMA_VALID) { + struct srb_iocb *nvme =3D &sp->u.iocb_cmd; + struct qla_hw_data *ha =3D sp->fcport->vha->hw; + + dma_unmap_single(&ha->pdev->dev, nvme->u.nvme.cmd_dma, + fd->rqstlen, DMA_TO_DEVICE); + sp->flags &=3D ~SRB_DMA_VALID; + } +} + static void qla_nvme_release_ls_cmd_kref(struct kref *kref) { struct srb *sp =3D container_of(kref, struct srb, cmd_kref); @@ -183,6 +200,8 @@ static void qla_nvme_release_ls_cmd_kref(struct kref *k= ref) spin_unlock_irqrestore(&priv->cmd_lock, flags); =20 fd =3D priv->fd; + + qla_nvme_ls_unmap(sp, fd); fd->done(fd, priv->comp_status); out: qla2x00_rel_sp(sp); @@ -353,6 +372,8 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *l= port, dma_sync_single_for_device(&ha->pdev->dev, nvme->u.nvme.cmd_dma, fd->rqstlen, DMA_TO_DEVICE); =20 + sp->flags |=3D SRB_DMA_VALID; + rval =3D qla2x00_start_sp(sp); if (rval !=3D QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x700e, @@ -360,6 +381,7 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *l= port, wake_up(&sp->nvme_ls_waitq); sp->priv =3D NULL; priv->sp =3D NULL; + qla_nvme_ls_unmap(sp, fd); qla2x00_rel_sp(sp); return rval; } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index abcd30917263..6dc2189badd3 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -728,7 +728,8 @@ void qla2x00_sp_compl(srb_t *sp, int res) struct scsi_cmnd *cmd =3D GET_CMD_SP(sp); struct completion *comp =3D sp->comp; =20 - sp->free(sp); + /* kref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); cmd->result =3D res; CMD_SP(cmd) =3D NULL; scsi_done(cmd); @@ -819,7 +820,8 @@ void qla2xxx_qpair_sp_compl(srb_t *sp, int res) struct scsi_cmnd *cmd =3D GET_CMD_SP(sp); struct completion *comp =3D sp->comp; =20 - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); cmd->result =3D res; CMD_SP(cmd) =3D NULL; scsi_done(cmd); @@ -919,6 +921,7 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scs= i_cmnd *cmd) goto qc24_target_busy; =20 sp =3D scsi_cmd_priv(cmd); + /* ref: INIT */ qla2xxx_init_sp(sp, vha, vha->hw->base_qpair, fcport); =20 sp->u.scmd.cmd =3D cmd; @@ -938,7 +941,8 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scs= i_cmnd *cmd) return 0; =20 qc24_host_busy_free_sp: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); =20 qc24_target_busy: return SCSI_MLQUEUE_TARGET_BUSY; @@ -1008,6 +1012,7 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct = scsi_cmnd *cmd, goto qc24_target_busy; =20 sp =3D scsi_cmd_priv(cmd); + /* ref: INIT */ qla2xxx_init_sp(sp, vha, qpair, fcport); =20 sp->u.scmd.cmd =3D cmd; @@ -1026,7 +1031,8 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct = scsi_cmnd *cmd, return 0; =20 qc24_host_busy_free_sp: - sp->free(sp); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); =20 qc24_target_busy: return SCSI_MLQUEUE_TARGET_BUSY; @@ -3748,8 +3754,7 @@ qla2x00_unmap_iobases(struct qla_hw_data *ha) if (ha->mqiobase) iounmap(ha->mqiobase); =20 - if ((IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) && - ha->msixbase) + if (ha->msixbase) iounmap(ha->msixbase); } } @@ -3891,6 +3896,8 @@ qla24xx_free_purex_list(struct purex_list *list) spin_lock_irqsave(&list->lock, flags); list_for_each_entry_safe(item, next, &list->head, list) { list_del(&item->list); + if (item =3D=3D &item->vha->default_item) + continue; kfree(item); } spin_unlock_irqrestore(&list->lock, flags); @@ -5526,6 +5533,11 @@ void qla2x00_relogin(struct scsi_qla_host *vha) memset(&ea, 0, sizeof(ea)); ea.fcport =3D fcport; qla24xx_handle_relogin_event(vha, &ea); + } else if (vha->hw->current_topology =3D=3D + ISP_CFG_NL && + IS_QLA2XXX_MIDTYPE(vha->hw)) { + (void)qla24xx_fcport_handle_login(vha, + fcport); } else if (vha->hw->current_topology =3D=3D ISP_CFG_NL) { fcport->login_retry--; @@ -7199,7 +7211,7 @@ static bool qla_do_heartbeat(struct scsi_qla_host *vh= a) return do_heartbeat; } =20 -static void qla_heart_beat(struct scsi_qla_host *vha) +static void qla_heart_beat(struct scsi_qla_host *vha, u16 dpc_started) { struct qla_hw_data *ha =3D vha->hw; =20 @@ -7209,8 +7221,19 @@ static void qla_heart_beat(struct scsi_qla_host *vha) if (vha->hw->flags.eeh_busy || qla2x00_chip_is_down(vha)) return; =20 - if (qla_do_heartbeat(vha)) + /* + * dpc thread cannot run if heartbeat is running at the same time. + * We also do not want to starve heartbeat task. Therefore, do + * heartbeat task at least once every 5 seconds. + */ + if (dpc_started && + time_before(jiffies, ha->last_heartbeat_run_jiffies + 5 * HZ)) + return; + + if (qla_do_heartbeat(vha)) { + ha->last_heartbeat_run_jiffies =3D jiffies; queue_work(ha->wq, &ha->heartbeat_work); + } } =20 /************************************************************************** @@ -7401,6 +7424,8 @@ qla2x00_timer(struct timer_list *t) start_dpc++; } =20 + /* borrowing w to signify dpc will run */ + w =3D 0; /* Schedule the DPC routine if needed */ if ((test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags) || @@ -7433,9 +7458,10 @@ qla2x00_timer(struct timer_list *t) test_bit(RELOGIN_NEEDED, &vha->dpc_flags), test_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags)); qla2xxx_wake_dpc(vha); + w =3D 1; } =20 - qla_heart_beat(vha); + qla_heart_beat(vha, w); =20 qla2x00_restart_timer(vha, WATCH_INTERVAL); } @@ -7633,7 +7659,7 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_= channel_state_t state) =20 switch (state) { case pci_channel_io_normal: - ha->flags.eeh_busy =3D 0; + qla_pci_set_eeh_busy(vha); if (ql2xmqsupport || ql2xnvmeenable) { set_bit(QPAIR_ONLINE_CHECK_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); @@ -7674,9 +7700,16 @@ qla2xxx_pci_mmio_enabled(struct pci_dev *pdev) "mmio enabled\n"); =20 ha->pci_error_state =3D QLA_PCI_MMIO_ENABLED; + if (IS_QLA82XX(ha)) return PCI_ERS_RESULT_RECOVERED; =20 + if (qla2x00_isp_reg_stat(ha)) { + ql_log(ql_log_info, base_vha, 0x803f, + "During mmio enabled, PCI/Register disconnect still detected.\n"); + goto out; + } + spin_lock_irqsave(&ha->hardware_lock, flags); if (IS_QLA2100(ha) || IS_QLA2200(ha)){ stat =3D rd_reg_word(®->hccr); @@ -7698,6 +7731,7 @@ qla2xxx_pci_mmio_enabled(struct pci_dev *pdev) "RISC paused -- mmio_enabled, Dumping firmware.\n"); qla2xxx_dump_fw(base_vha); } +out: /* set PCI_ERS_RESULT_NEED_RESET to trigger call to qla2xxx_pci_slot_rese= t */ ql_dbg(ql_dbg_aer, base_vha, 0x600d, "mmio enabled returning.\n"); diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index a0aeba69513d..c092a6b1ced4 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -844,7 +844,7 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt= _addr) ha->flt_region_nvram =3D start; break; case FLT_REG_IMG_PRI_27XX: - if (IS_QLA27XX(ha) && !IS_QLA28XX(ha)) + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) ha->flt_region_img_status_pri =3D start; break; case FLT_REG_IMG_SEC_27XX: @@ -1356,7 +1356,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, __le32= *dwptr, uint32_t faddr, flash_data_addr(ha, faddr), le32_to_cpu(*dwptr)); if (ret) { ql_dbg(ql_dbg_user, vha, 0x7006, - "Failed slopw write %x (%x)\n", faddr, *dwptr); + "Failed slow write %x (%x)\n", faddr, *dwptr); break; } } diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_t= arget.c index 8993d438e0b7..b109716d44fb 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -620,7 +620,7 @@ static void qla2x00_async_nack_sp_done(srb_t *sp, int r= es) } spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); =20 - sp->free(sp); + kref_put(&sp->cmd_kref, qla2x00_sp_release); } =20 int qla24xx_async_notify_ack(scsi_qla_host_t *vha, fc_port_t *fcport, @@ -656,12 +656,10 @@ int qla24xx_async_notify_ack(scsi_qla_host_t *vha, fc= _port_t *fcport, =20 sp->type =3D type; sp->name =3D "nack"; - - sp->u.iocb_cmd.timeout =3D qla2x00_async_iocb_timeout; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha)+2); + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, + qla2x00_async_nack_sp_done); =20 sp->u.iocb_cmd.u.nack.ntfy =3D ntfy; - sp->done =3D qla2x00_async_nack_sp_done; =20 ql_dbg(ql_dbg_disc, vha, 0x20f4, "Async-%s %8phC hndl %x %s\n", @@ -674,7 +672,7 @@ int qla24xx_async_notify_ack(scsi_qla_host_t *vha, fc_p= ort_t *fcport, return rval; =20 done_free_sp: - sp->free(sp); + kref_put(&sp->cmd_kref, qla2x00_sp_release); done: fcport->flags &=3D ~FCF_ASYNC_SENT; return rval; @@ -3320,6 +3318,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xm= it_type, "RESET-RSP online/active/old-count/new-count =3D %d/%d/%d/%d.\n", vha->flags.online, qla2x00_reset_active(vha), cmd->reset_count, qpair->chip_reset); + res =3D 0; goto out_unmap_unlock; } =20 @@ -7221,8 +7220,7 @@ qlt_probe_one_stage1(struct scsi_qla_host *base_vha, = struct qla_hw_data *ha) if (!QLA_TGT_MODE_ENABLED()) return; =20 - if ((ql2xenablemsix =3D=3D 0) || IS_QLA83XX(ha) || IS_QLA27XX(ha) || - IS_QLA28XX(ha)) { + if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { ISP_ATIO_Q_IN(base_vha) =3D &ha->mqiobase->isp25mq.atio_q_in; ISP_ATIO_Q_OUT(base_vha) =3D &ha->mqiobase->isp25mq.atio_q_out; } else { diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmp= l.c index 26c13a953b97..b0a74b036cf4 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.c +++ b/drivers/scsi/qla2xxx/qla_tmpl.c @@ -435,8 +435,13 @@ qla27xx_fwdt_entry_t266(struct scsi_qla_host *vha, { ql_dbg(ql_dbg_misc, vha, 0xd20a, "%s: reset risc [%lx]\n", __func__, *len); - if (buf) - WARN_ON_ONCE(qla24xx_soft_reset(vha->hw) !=3D QLA_SUCCESS); + if (buf) { + if (qla24xx_soft_reset(vha->hw) !=3D QLA_SUCCESS) { + ql_dbg(ql_dbg_async, vha, 0x5001, + "%s: unable to soft reset\n", __func__); + return INVALID_ENTRY; + } + } =20 return qla27xx_next_entry(ent); } diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 2371edbc3af4..d327e1fa5c0b 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -483,8 +483,13 @@ static void scsi_report_sense(struct scsi_device *sdev, =20 if (sshdr->asc =3D=3D 0x29) { evt_type =3D SDEV_EVT_POWER_ON_RESET_OCCURRED; - sdev_printk(KERN_WARNING, sdev, - "Power-on or device reset occurred\n"); + /* + * Do not print message if it is an expected side-effect + * of runtime PM. + */ + if (!sdev->silence_suspend) + sdev_printk(KERN_WARNING, sdev, + "Power-on or device reset occurred\n"); } =20 if (sshdr->asc =3D=3D 0x2a && sshdr->ascq =3D=3D 0x01) { diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport= _fc.c index 60e406bcf42a..a2524106206d 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -34,7 +34,7 @@ static int fc_bsg_hostadd(struct Scsi_Host *, struct fc_h= ost_attrs *); static int fc_bsg_rportadd(struct Scsi_Host *, struct fc_rport *); static void fc_bsg_remove(struct request_queue *); static void fc_bsg_goose_queue(struct fc_rport *); -static void fc_li_stats_update(struct fc_fn_li_desc *li_desc, +static void fc_li_stats_update(u16 event_type, struct fc_fpin_stats *stats); static void fc_delivery_stats_update(u32 reason_code, struct fc_fpin_stats *stats); @@ -670,42 +670,34 @@ fc_find_rport_by_wwpn(struct Scsi_Host *shost, u64 ww= pn) EXPORT_SYMBOL(fc_find_rport_by_wwpn); =20 static void -fc_li_stats_update(struct fc_fn_li_desc *li_desc, +fc_li_stats_update(u16 event_type, struct fc_fpin_stats *stats) { - stats->li +=3D be32_to_cpu(li_desc->event_count); - switch (be16_to_cpu(li_desc->event_type)) { + stats->li++; + switch (event_type) { case FPIN_LI_UNKNOWN: - stats->li_failure_unknown +=3D - be32_to_cpu(li_desc->event_count); + stats->li_failure_unknown++; break; case FPIN_LI_LINK_FAILURE: - stats->li_link_failure_count +=3D - be32_to_cpu(li_desc->event_count); + stats->li_link_failure_count++; break; case FPIN_LI_LOSS_OF_SYNC: - stats->li_loss_of_sync_count +=3D - be32_to_cpu(li_desc->event_count); + stats->li_loss_of_sync_count++; break; case FPIN_LI_LOSS_OF_SIG: - stats->li_loss_of_signals_count +=3D - be32_to_cpu(li_desc->event_count); + stats->li_loss_of_signals_count++; break; case FPIN_LI_PRIM_SEQ_ERR: - stats->li_prim_seq_err_count +=3D - be32_to_cpu(li_desc->event_count); + stats->li_prim_seq_err_count++; break; case FPIN_LI_INVALID_TX_WD: - stats->li_invalid_tx_word_count +=3D - be32_to_cpu(li_desc->event_count); + stats->li_invalid_tx_word_count++; break; case FPIN_LI_INVALID_CRC: - stats->li_invalid_crc_count +=3D - be32_to_cpu(li_desc->event_count); + stats->li_invalid_crc_count++; break; case FPIN_LI_DEVICE_SPEC: - stats->li_device_specific +=3D - be32_to_cpu(li_desc->event_count); + stats->li_device_specific++; break; } } @@ -767,6 +759,7 @@ fc_fpin_li_stats_update(struct Scsi_Host *shost, struct= fc_tlv_desc *tlv) struct fc_rport *attach_rport =3D NULL; struct fc_host_attrs *fc_host =3D shost_to_fc_host(shost); struct fc_fn_li_desc *li_desc =3D (struct fc_fn_li_desc *)tlv; + u16 event_type =3D be16_to_cpu(li_desc->event_type); u64 wwpn; =20 rport =3D fc_find_rport_by_wwpn(shost, @@ -775,7 +768,7 @@ fc_fpin_li_stats_update(struct Scsi_Host *shost, struct= fc_tlv_desc *tlv) (rport->roles & FC_PORT_ROLE_FCP_TARGET || rport->roles & FC_PORT_ROLE_NVME_TARGET)) { attach_rport =3D rport; - fc_li_stats_update(li_desc, &attach_rport->fpin_stats); + fc_li_stats_update(event_type, &attach_rport->fpin_stats); } =20 if (be32_to_cpu(li_desc->pname_count) > 0) { @@ -789,14 +782,14 @@ fc_fpin_li_stats_update(struct Scsi_Host *shost, stru= ct fc_tlv_desc *tlv) rport->roles & FC_PORT_ROLE_NVME_TARGET)) { if (rport =3D=3D attach_rport) continue; - fc_li_stats_update(li_desc, + fc_li_stats_update(event_type, &rport->fpin_stats); } } } =20 if (fc_host->port_name =3D=3D be64_to_cpu(li_desc->attached_wwpn)) - fc_li_stats_update(li_desc, &fc_host->fpin_stats); + fc_li_stats_update(event_type, &fc_host->fpin_stats); } =20 /* diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 65875a598d62..dfca484dd0c4 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -3754,7 +3754,8 @@ static int sd_suspend_common(struct device *dev, bool= ignore_stop_errors) return 0; =20 if (sdkp->WCE && sdkp->media_present) { - sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); + if (!sdkp->device->silence_suspend) + sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); ret =3D sd_sync_cache(sdkp, &sshdr); =20 if (ret) { @@ -3776,7 +3777,8 @@ static int sd_suspend_common(struct device *dev, bool= ignore_stop_errors) } =20 if (sdkp->device->manage_start_stop) { - sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); + if (!sdkp->device->silence_suspend) + sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); /* an error is not worth aborting a system sleep */ ret =3D sd_start_stop_device(sdkp, 0); if (ignore_stop_errors) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 9e7aa3a2fdf5..4faea70561b8 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -585,7 +585,12 @@ static void ufshcd_print_pwr_info(struct ufs_hba *hba) "INVALID MODE", }; =20 - dev_err(hba->dev, "%s:[RX, TX]: gear=3D[%d, %d], lane[%d, %d], pwr[%s, %s= ], rate =3D %d\n", + /* + * Using dev_dbg to avoid messages during runtime PM to avoid + * never-ending cycles of messages written back to storage by user space + * causing runtime resume, causing more messages and so on. + */ + dev_dbg(hba->dev, "%s:[RX, TX]: gear=3D[%d, %d], lane[%d, %d], pwr[%s, %s= ], rate =3D %d\n", __func__, hba->pwr_info.gear_rx, hba->pwr_info.gear_tx, hba->pwr_info.lane_rx, hba->pwr_info.lane_tx, @@ -4999,6 +5004,12 @@ static int ufshcd_slave_configure(struct scsi_device= *sdev) pm_runtime_get_noresume(&sdev->sdev_gendev); else if (ufshcd_is_rpm_autosuspend_allowed(hba)) sdev->rpm_autosuspend =3D 1; + /* + * Do not print messages during runtime PM to avoid never-ending cycles + * of messages written back to storage by user space causing runtime + * resume, causing more messages and so on. + */ + sdev->silence_suspend =3D 1; =20 ufshcd_crypto_register(hba, q); =20 @@ -7285,7 +7296,13 @@ static u32 ufshcd_find_max_sup_active_icc_level(stru= ct ufs_hba *hba, =20 if (!hba->vreg_info.vcc || !hba->vreg_info.vccq || !hba->vreg_info.vccq2) { - dev_err(hba->dev, + /* + * Using dev_dbg to avoid messages during runtime PM to avoid + * never-ending cycles of messages written back to storage by + * user space causing runtime resume, causing more messages and + * so on. + */ + dev_dbg(hba->dev, "%s: Regulator capability was not set, actvIccLevel=3D%d", __func__, icc_level); goto out; diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/m= tk-pm-domains.c index b762bc40f56b..afd2fd74802d 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.c +++ b/drivers/soc/mediatek/mtk-pm-domains.c @@ -443,6 +443,9 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys = *scpsys, struct device_no pd->genpd.power_off =3D scpsys_power_off; pd->genpd.power_on =3D scpsys_power_on; =20 + if (MTK_SCPD_CAPS(pd, MTK_SCPD_ACTIVE_WAKEUP)) + pd->genpd.flags |=3D GENPD_FLAG_ACTIVE_WAKEUP; + if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF)) pm_genpd_init(&pd->genpd, NULL, true); else diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c index d2dacbbaafbd..97fd24c178f8 100644 --- a/drivers/soc/qcom/ocmem.c +++ b/drivers/soc/qcom/ocmem.c @@ -206,6 +206,7 @@ struct ocmem *of_get_ocmem(struct device *dev) ocmem =3D platform_get_drvdata(pdev); if (!ocmem) { dev_err(dev, "Cannot get ocmem\n"); + put_device(&pdev->dev); return ERR_PTR(-ENODEV); } return ocmem; diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c index 34acf58bbb0d..55c156aaf68a 100644 --- a/drivers/soc/qcom/qcom_aoss.c +++ b/drivers/soc/qcom/qcom_aoss.c @@ -451,7 +451,11 @@ struct qmp *qmp_get(struct device *dev) =20 qmp =3D platform_get_drvdata(pdev); =20 - return qmp ? qmp : ERR_PTR(-EPROBE_DEFER); + if (!qmp) { + put_device(&pdev->dev); + return ERR_PTR(-EPROBE_DEFER); + } + return qmp; } EXPORT_SYMBOL(qmp_get); =20 @@ -497,7 +501,7 @@ static int qmp_probe(struct platform_device *pdev) } =20 irq =3D platform_get_irq(pdev, 0); - ret =3D devm_request_irq(&pdev->dev, irq, qmp_intr, IRQF_ONESHOT, + ret =3D devm_request_irq(&pdev->dev, irq, qmp_intr, 0, "aoss-qmp", qmp); if (ret < 0) { dev_err(&pdev->dev, "failed to request interrupt\n"); diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c index 4f69fb9b2e0e..69b587822e39 100644 --- a/drivers/soc/qcom/rpmpd.c +++ b/drivers/soc/qcom/rpmpd.c @@ -570,6 +570,9 @@ static int rpmpd_probe(struct platform_device *pdev) =20 data->domains =3D devm_kcalloc(&pdev->dev, num, sizeof(*data->domains), GFP_KERNEL); + if (!data->domains) + return -ENOMEM; + data->num_domains =3D num; =20 for (i =3D 0; i < num; i++) { diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c index 72386bd393fe..2f03ced0f411 100644 --- a/drivers/soc/ti/wkup_m3_ipc.c +++ b/drivers/soc/ti/wkup_m3_ipc.c @@ -450,9 +450,9 @@ static int wkup_m3_ipc_probe(struct platform_device *pd= ev) return PTR_ERR(m3_ipc->ipc_mem_base); =20 irq =3D platform_get_irq(pdev, 0); - if (!irq) { + if (irq < 0) { dev_err(&pdev->dev, "no irq resource\n"); - return -ENXIO; + return irq; } =20 ret =3D devm_request_irq(dev, irq, wkup_m3_txev_handler, diff --git a/drivers/soundwire/dmi-quirks.c b/drivers/soundwire/dmi-quirks.c index 0ca2a3e3a02e..747983743a14 100644 --- a/drivers/soundwire/dmi-quirks.c +++ b/drivers/soundwire/dmi-quirks.c @@ -59,7 +59,7 @@ static const struct dmi_system_id adr_remap_quirk_table[]= =3D { { .matches =3D { DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Convertible"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Conv"), }, .driver_data =3D (void *)intel_tgl_bios, }, diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 78037ffdb09b..f72d36654ac2 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -448,8 +448,8 @@ static void intel_shim_wake(struct sdw_intel *sdw, bool= wake_enable) =20 /* Clear wake status */ wake_sts =3D intel_readw(shim, SDW_SHIM_WAKESTS); - wake_sts |=3D (SDW_SHIM_WAKEEN_ENABLE << link_id); - intel_writew(shim, SDW_SHIM_WAKESTS_STATUS, wake_sts); + wake_sts |=3D (SDW_SHIM_WAKESTS_STATUS << link_id); + intel_writew(shim, SDW_SHIM_WAKESTS, wake_sts); } mutex_unlock(sdw->link_res->shim_lock); } diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c index b6c7467f0b59..d403a7a3021d 100644 --- a/drivers/spi/spi-fsi.c +++ b/drivers/spi/spi-fsi.c @@ -25,6 +25,7 @@ =20 #define SPI_FSI_BASE 0x70000 #define SPI_FSI_INIT_TIMEOUT_MS 1000 +#define SPI_FSI_STATUS_TIMEOUT_MS 100 #define SPI_FSI_MAX_RX_SIZE 8 #define SPI_FSI_MAX_TX_SIZE 40 =20 @@ -299,6 +300,7 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx, struct spi_transfer *transfer) { int rc =3D 0; + unsigned long end; u64 status =3D 0ULL; =20 if (transfer->tx_buf) { @@ -315,10 +317,14 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx, if (rc) return rc; =20 + end =3D jiffies + msecs_to_jiffies(SPI_FSI_STATUS_TIMEOUT_MS); do { rc =3D fsi_spi_status(ctx, &status, "TX"); if (rc) return rc; + + if (time_after(jiffies, end)) + return -ETIMEDOUT; } while (status & SPI_FSI_STATUS_TDR_FULL); =20 sent +=3D nb; @@ -329,10 +335,14 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx, u8 *rx =3D transfer->rx_buf; =20 while (transfer->len > recv) { + end =3D jiffies + msecs_to_jiffies(SPI_FSI_STATUS_TIMEOUT_MS); do { rc =3D fsi_spi_status(ctx, &status, "RX"); if (rc) return rc; + + if (time_after(jiffies, end)) + return -ETIMEDOUT; } while (!(status & SPI_FSI_STATUS_RDR_FULL)); =20 rc =3D fsi_spi_read_reg(ctx, SPI_FSI_DATA_RX, &in); diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 753bd313e6fd..2ca19b01948a 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -43,8 +43,11 @@ #define SPI_CFG1_PACKET_LOOP_OFFSET 8 #define SPI_CFG1_PACKET_LENGTH_OFFSET 16 #define SPI_CFG1_GET_TICK_DLY_OFFSET 29 +#define SPI_CFG1_GET_TICK_DLY_OFFSET_V1 30 =20 #define SPI_CFG1_GET_TICK_DLY_MASK 0xe0000000 +#define SPI_CFG1_GET_TICK_DLY_MASK_V1 0xc0000000 + #define SPI_CFG1_CS_IDLE_MASK 0xff #define SPI_CFG1_PACKET_LOOP_MASK 0xff00 #define SPI_CFG1_PACKET_LENGTH_MASK 0x3ff0000 @@ -346,9 +349,15 @@ static int mtk_spi_prepare_message(struct spi_master *= master, =20 /* tick delay */ reg_val =3D readl(mdata->base + SPI_CFG1_REG); - reg_val &=3D ~SPI_CFG1_GET_TICK_DLY_MASK; - reg_val |=3D ((chip_config->tick_delay & 0x7) - << SPI_CFG1_GET_TICK_DLY_OFFSET); + if (mdata->dev_comp->enhance_timing) { + reg_val &=3D ~SPI_CFG1_GET_TICK_DLY_MASK; + reg_val |=3D ((chip_config->tick_delay & 0x7) + << SPI_CFG1_GET_TICK_DLY_OFFSET); + } else { + reg_val &=3D ~SPI_CFG1_GET_TICK_DLY_MASK_V1; + reg_val |=3D ((chip_config->tick_delay & 0x3) + << SPI_CFG1_GET_TICK_DLY_OFFSET_V1); + } writel(reg_val, mdata->base + SPI_CFG1_REG); =20 /* set hw cs timing */ diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c index 45889947afed..03fce4493aa7 100644 --- a/drivers/spi/spi-mxic.c +++ b/drivers/spi/spi-mxic.c @@ -304,25 +304,21 @@ static int mxic_spi_data_xfer(struct mxic_spi *mxic, = const void *txbuf, =20 writel(data, mxic->regs + TXD(nbytes % 4)); =20 + ret =3D readl_poll_timeout(mxic->regs + INT_STS, sts, + sts & INT_TX_EMPTY, 0, USEC_PER_SEC); + if (ret) + return ret; + + ret =3D readl_poll_timeout(mxic->regs + INT_STS, sts, + sts & INT_RX_NOT_EMPTY, 0, + USEC_PER_SEC); + if (ret) + return ret; + + data =3D readl(mxic->regs + RXD); if (rxbuf) { - ret =3D readl_poll_timeout(mxic->regs + INT_STS, sts, - sts & INT_TX_EMPTY, 0, - USEC_PER_SEC); - if (ret) - return ret; - - ret =3D readl_poll_timeout(mxic->regs + INT_STS, sts, - sts & INT_RX_NOT_EMPTY, 0, - USEC_PER_SEC); - if (ret) - return ret; - - data =3D readl(mxic->regs + RXD); data >>=3D (8 * (4 - nbytes)); memcpy(rxbuf + pos, &data, nbytes); - WARN_ON(readl(mxic->regs + INT_STS) & INT_RX_NOT_EMPTY); - } else { - readl(mxic->regs + RXD); } WARN_ON(readl(mxic->regs + INT_STS) & INT_RX_NOT_EMPTY); =20 diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 2e134eb4bd2c..6502fda6243e 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -76,14 +76,23 @@ static bool lpss_dma_filter(struct dma_chan *chan, void= *param) return true; } =20 +static void lpss_dma_put_device(void *dma_dev) +{ + pci_dev_put(dma_dev); +} + static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) { struct pci_dev *dma_dev; + int ret; =20 c->num_chipselect =3D 1; c->max_clk_rate =3D 50000000; =20 dma_dev =3D pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); + ret =3D devm_add_action_or_reset(&dev->dev, lpss_dma_put_device, dma_dev); + if (ret) + return ret; =20 if (c->tx_param) { struct dw_dma_slave *slave =3D c->tx_param; @@ -107,8 +116,9 @@ static int lpss_spi_setup(struct pci_dev *dev, struct p= xa_spi_info *c) =20 static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) { - struct pci_dev *dma_dev =3D pci_get_slot(dev->bus, PCI_DEVFN(21, 0)); struct dw_dma_slave *tx, *rx; + struct pci_dev *dma_dev; + int ret; =20 switch (PCI_FUNC(dev->devfn)) { case 0: @@ -133,6 +143,11 @@ static int mrfld_spi_setup(struct pci_dev *dev, struct= pxa_spi_info *c) return -ENODEV; } =20 + dma_dev =3D pci_get_slot(dev->bus, PCI_DEVFN(21, 0)); + ret =3D devm_add_action_or_reset(&dev->dev, lpss_dma_put_device, dma_dev); + if (ret) + return ret; + tx =3D c->tx_param; tx->dma_dev =3D &dma_dev->dev; =20 diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index e9de1d958bbd..8f345247a8c3 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -1352,6 +1352,10 @@ static int tegra_spi_probe(struct platform_device *p= dev) tspi->phys =3D r->start; =20 spi_irq =3D platform_get_irq(pdev, 0); + if (spi_irq < 0) { + ret =3D spi_irq; + goto exit_free_master; + } tspi->irq =3D spi_irq; =20 tspi->clk =3D devm_clk_get(&pdev->dev, "spi"); diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slin= k.c index e8204e155484..746bbafa1378 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -1003,14 +1003,8 @@ static int tegra_slink_probe(struct platform_device = *pdev) struct resource *r; int ret, spi_irq; const struct tegra_slink_chip_data *cdata =3D NULL; - const struct of_device_id *match; =20 - match =3D of_match_device(tegra_slink_of_match, &pdev->dev); - if (!match) { - dev_err(&pdev->dev, "Error: No device match found\n"); - return -ENODEV; - } - cdata =3D match->data; + cdata =3D of_device_get_match_data(&pdev->dev); =20 master =3D spi_alloc_master(&pdev->dev, sizeof(*tspi)); if (!master) { diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-qua= d.c index c0f9a75b44b5..27e6ce4fbd35 100644 --- a/drivers/spi/spi-tegra210-quad.c +++ b/drivers/spi/spi-tegra210-quad.c @@ -1249,6 +1249,8 @@ static int tegra_qspi_probe(struct platform_device *p= dev) =20 tqspi->phys =3D r->start; qspi_irq =3D platform_get_irq(pdev, 0); + if (qspi_irq < 0) + return qspi_irq; tqspi->irq =3D qspi_irq; =20 tqspi->clk =3D devm_clk_get(&pdev->dev, "qspi"); diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index 328b6559bb19..2b5afae8ff7f 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -1172,7 +1172,10 @@ static int zynqmp_qspi_probe(struct platform_device = *pdev) goto clk_dis_all; } =20 - dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); + ret =3D dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); + if (ret) + goto clk_dis_all; + ctlr->bits_per_word_mask =3D SPI_BPW_MASK(8); ctlr->num_chipselect =3D GQSPI_DEFAULT_NUM_CS; ctlr->mem_ops =3D &zynqmp_qspi_mem_ops; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 8ba87b7f8f1a..4e459516b74c 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1021,10 +1021,10 @@ int spi_map_buf(struct spi_controller *ctlr, struct= device *dev, int i, ret; =20 if (vmalloced_buf || kmap_buf) { - desc_len =3D min_t(int, max_seg_size, PAGE_SIZE); + desc_len =3D min_t(unsigned long, max_seg_size, PAGE_SIZE); sgs =3D DIV_ROUND_UP(len + offset_in_page(buf), desc_len); } else if (virt_addr_valid(buf)) { - desc_len =3D min_t(int, max_seg_size, ctlr->max_dma_len); + desc_len =3D min_t(size_t, max_seg_size, ctlr->max_dma_len); sgs =3D DIV_ROUND_UP(len, desc_len); } else { return -EINVAL; diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad= 7280a.c index fef0055b8990..20183b2ea127 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -107,9 +107,9 @@ static unsigned int ad7280a_devaddr(unsigned int addr) { return ((addr & 0x1) << 4) | - ((addr & 0x2) << 3) | + ((addr & 0x2) << 2) | (addr & 0x4) | - ((addr & 0x8) >> 3) | + ((addr & 0x8) >> 2) | ((addr & 0x10) >> 4); } =20 diff --git a/drivers/staging/media/atomisp/pci/atomisp_acc.c b/drivers/stag= ing/media/atomisp/pci/atomisp_acc.c index 9a1751895ab0..28cb271663c4 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_acc.c +++ b/drivers/staging/media/atomisp/pci/atomisp_acc.c @@ -439,6 +439,18 @@ int atomisp_acc_s_mapped_arg(struct atomisp_sub_device= *asd, return 0; } =20 +static void atomisp_acc_unload_some_extensions(struct atomisp_sub_device *= asd, + int i, + struct atomisp_acc_fw *acc_fw) +{ + while (--i >=3D 0) { + if (acc_fw->flags & acc_flag_to_pipe[i].flag) { + atomisp_css_unload_acc_extension(asd, acc_fw->fw, + acc_flag_to_pipe[i].pipe_id); + } + } +} + /* * Appends the loaded acceleration binary extensions to the * current ISP mode. Must be called just before sh_css_start(). @@ -479,16 +491,20 @@ int atomisp_acc_load_extensions(struct atomisp_sub_de= vice *asd) acc_fw->fw, acc_flag_to_pipe[i].pipe_id, acc_fw->type); - if (ret) + if (ret) { + atomisp_acc_unload_some_extensions(asd, i, acc_fw); goto error; + } =20 ext_loaded =3D true; } } =20 ret =3D atomisp_css_set_acc_parameters(acc_fw); - if (ret < 0) + if (ret < 0) { + atomisp_acc_unload_some_extensions(asd, i, acc_fw); goto error; + } } =20 if (!ext_loaded) @@ -497,6 +513,7 @@ int atomisp_acc_load_extensions(struct atomisp_sub_devi= ce *asd) ret =3D atomisp_css_update_stream(asd); if (ret) { dev_err(isp->dev, "%s: update stream failed.\n", __func__); + atomisp_acc_unload_extensions(asd); goto error; } =20 @@ -504,13 +521,6 @@ int atomisp_acc_load_extensions(struct atomisp_sub_dev= ice *asd) return 0; =20 error: - while (--i >=3D 0) { - if (acc_fw->flags & acc_flag_to_pipe[i].flag) { - atomisp_css_unload_acc_extension(asd, acc_fw->fw, - acc_flag_to_pipe[i].pipe_id); - } - } - list_for_each_entry_continue_reverse(acc_fw, &asd->acc.fw, list) { if (acc_fw->type !=3D ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT && acc_fw->type !=3D ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER) diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/dr= ivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index 62dc06e22476..cd0a771454da 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -729,6 +729,21 @@ static int axp_regulator_set(struct device *dev, struc= t gmin_subdev *gs, return 0; } =20 +/* + * Some boards contain a hw-bug where turning eldo2 back on after having t= urned + * it off causes the CPLM3218 ambient-light-sensor on the image-sensor's I= 2C bus + * to crash, hanging the bus. Do not turn eldo2 off on these systems. + */ +static const struct dmi_system_id axp_leave_eldo2_on_ids[] =3D { + { + .matches =3D { + DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"), + DMI_MATCH(DMI_PRODUCT_NAME, "SurfTab duo W1 10.1 (VT4)"), + }, + }, + { } +}; + static int axp_v1p8_on(struct device *dev, struct gmin_subdev *gs) { int ret; @@ -763,6 +778,9 @@ static int axp_v1p8_off(struct device *dev, struct gmin= _subdev *gs) if (ret) return ret; =20 + if (dmi_check_system(axp_leave_eldo2_on_ids)) + return 0; + ret =3D axp_regulator_set(dev, gs, gs->eldo2_sel_reg, gs->eldo2_1p8v, ELDO_CTRL_REG, gs->eldo2_ctrl_shift, false); return ret; diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm.c b/drivers/staging/= media/atomisp/pci/hmm/hmm.c index 6a5ee4607089..c1cda16f2dc0 100644 --- a/drivers/staging/media/atomisp/pci/hmm/hmm.c +++ b/drivers/staging/media/atomisp/pci/hmm/hmm.c @@ -39,7 +39,7 @@ struct hmm_bo_device bo_device; struct hmm_pool dynamic_pool; struct hmm_pool reserved_pool; -static ia_css_ptr dummy_ptr; +static ia_css_ptr dummy_ptr =3D mmgr_EXCEPTION; static bool hmm_initialized; struct _hmm_mem_stat hmm_mem_stat; =20 @@ -209,7 +209,7 @@ int hmm_init(void) =20 void hmm_cleanup(void) { - if (!dummy_ptr) + if (dummy_ptr =3D=3D mmgr_EXCEPTION) return; sysfs_remove_group(&atomisp_dev->kobj, atomisp_attribute_group); =20 @@ -288,7 +288,8 @@ void hmm_free(ia_css_ptr virt) =20 dev_dbg(atomisp_dev, "%s: free 0x%08x\n", __func__, virt); =20 - WARN_ON(!virt); + if (WARN_ON(virt =3D=3D mmgr_EXCEPTION)) + return; =20 bo =3D hmm_bo_device_search_start(&bo_device, (unsigned int)virt); =20 diff --git a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c b/drivers/st= aging/media/hantro/hantro_h1_jpeg_enc.c index 9cd713c02a45..686d813f5c62 100644 --- a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c +++ b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c @@ -23,7 +23,7 @@ static void hantro_h1_set_src_img_ctrl(struct hantro_dev = *vpu, =20 reg =3D H1_REG_IN_IMG_CTRL_ROW_LEN(pix_fmt->width) | H1_REG_IN_IMG_CTRL_OVRFLR_D4(0) - | H1_REG_IN_IMG_CTRL_OVRFLB_D4(0) + | H1_REG_IN_IMG_CTRL_OVRFLB(0) | H1_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt); vepu_write_relaxed(vpu, reg, H1_REG_IN_IMG_CTRL); } diff --git a/drivers/staging/media/hantro/hantro_h1_regs.h b/drivers/stagin= g/media/hantro/hantro_h1_regs.h index d6e9825bb5c7..30e7e7b920b5 100644 --- a/drivers/staging/media/hantro/hantro_h1_regs.h +++ b/drivers/staging/media/hantro/hantro_h1_regs.h @@ -47,7 +47,7 @@ #define H1_REG_IN_IMG_CTRL 0x03c #define H1_REG_IN_IMG_CTRL_ROW_LEN(x) ((x) << 12) #define H1_REG_IN_IMG_CTRL_OVRFLR_D4(x) ((x) << 10) -#define H1_REG_IN_IMG_CTRL_OVRFLB_D4(x) ((x) << 6) +#define H1_REG_IN_IMG_CTRL_OVRFLB(x) ((x) << 6) #define H1_REG_IN_IMG_CTRL_FMT(x) ((x) << 2) #define H1_REG_ENC_CTRL0 0x040 #define H1_REG_ENC_CTRL0_INIT_QP(x) ((x) << 26) diff --git a/drivers/staging/media/imx/imx7-mipi-csis.c b/drivers/staging/m= edia/imx/imx7-mipi-csis.c index 2b73fa55c938..9ea723bb5f20 100644 --- a/drivers/staging/media/imx/imx7-mipi-csis.c +++ b/drivers/staging/media/imx/imx7-mipi-csis.c @@ -32,7 +32,6 @@ #include =20 #define CSIS_DRIVER_NAME "imx7-mipi-csis" -#define CSIS_SUBDEV_NAME CSIS_DRIVER_NAME =20 #define CSIS_PAD_SINK 0 #define CSIS_PAD_SOURCE 1 @@ -311,7 +310,6 @@ struct csi_state { struct reset_control *mrst; struct regulator *mipi_phy_regulator; const struct mipi_csis_info *info; - u8 index; =20 struct v4l2_subdev sd; struct media_pad pads[CSIS_PADS_NUM]; @@ -1303,8 +1301,8 @@ static int mipi_csis_subdev_init(struct csi_state *st= ate) =20 v4l2_subdev_init(sd, &mipi_csis_subdev_ops); sd->owner =3D THIS_MODULE; - snprintf(sd->name, sizeof(sd->name), "%s.%d", - CSIS_SUBDEV_NAME, state->index); + snprintf(sd->name, sizeof(sd->name), "csis-%s", + dev_name(state->dev)); =20 sd->flags |=3D V4L2_SUBDEV_FL_HAS_DEVNODE; sd->ctrl_handler =3D NULL; diff --git a/drivers/staging/media/imx/imx8mq-mipi-csi2.c b/drivers/staging= /media/imx/imx8mq-mipi-csi2.c index 7adbdd14daa9..3b9fa75efac6 100644 --- a/drivers/staging/media/imx/imx8mq-mipi-csi2.c +++ b/drivers/staging/media/imx/imx8mq-mipi-csi2.c @@ -398,9 +398,6 @@ static int imx8mq_mipi_csi_s_stream(struct v4l2_subdev = *sd, int enable) struct csi_state *state =3D mipi_sd_to_csi2_state(sd); int ret =3D 0; =20 - imx8mq_mipi_csi_write(state, CSI2RX_IRQ_MASK, - CSI2RX_IRQ_MASK_ULPS_STATUS_CHANGE); - if (enable) { ret =3D pm_runtime_resume_and_get(state->dev); if (ret < 0) @@ -696,7 +693,7 @@ static int imx8mq_mipi_csi_async_register(struct csi_st= ate *state) * Suspend/resume */ =20 -static int imx8mq_mipi_csi_pm_suspend(struct device *dev, bool runtime) +static int imx8mq_mipi_csi_pm_suspend(struct device *dev) { struct v4l2_subdev *sd =3D dev_get_drvdata(dev); struct csi_state *state =3D mipi_sd_to_csi2_state(sd); @@ -708,36 +705,21 @@ static int imx8mq_mipi_csi_pm_suspend(struct device *= dev, bool runtime) imx8mq_mipi_csi_stop_stream(state); imx8mq_mipi_csi_clk_disable(state); state->state &=3D ~ST_POWERED; - if (!runtime) - state->state |=3D ST_SUSPENDED; } =20 mutex_unlock(&state->lock); =20 - ret =3D icc_set_bw(state->icc_path, 0, 0); - if (ret) - dev_err(dev, "icc_set_bw failed with %d\n", ret); - return ret ? -EAGAIN : 0; } =20 -static int imx8mq_mipi_csi_pm_resume(struct device *dev, bool runtime) +static int imx8mq_mipi_csi_pm_resume(struct device *dev) { struct v4l2_subdev *sd =3D dev_get_drvdata(dev); struct csi_state *state =3D mipi_sd_to_csi2_state(sd); int ret =3D 0; =20 - ret =3D icc_set_bw(state->icc_path, 0, state->icc_path_bw); - if (ret) { - dev_err(dev, "icc_set_bw failed with %d\n", ret); - return ret; - } - mutex_lock(&state->lock); =20 - if (!runtime && !(state->state & ST_SUSPENDED)) - goto unlock; - if (!(state->state & ST_POWERED)) { state->state |=3D ST_POWERED; ret =3D imx8mq_mipi_csi_clk_enable(state); @@ -758,22 +740,60 @@ static int imx8mq_mipi_csi_pm_resume(struct device *d= ev, bool runtime) =20 static int __maybe_unused imx8mq_mipi_csi_suspend(struct device *dev) { - return imx8mq_mipi_csi_pm_suspend(dev, false); + struct v4l2_subdev *sd =3D dev_get_drvdata(dev); + struct csi_state *state =3D mipi_sd_to_csi2_state(sd); + int ret; + + ret =3D imx8mq_mipi_csi_pm_suspend(dev); + if (ret) + return ret; + + state->state |=3D ST_SUSPENDED; + + return ret; } =20 static int __maybe_unused imx8mq_mipi_csi_resume(struct device *dev) { - return imx8mq_mipi_csi_pm_resume(dev, false); + struct v4l2_subdev *sd =3D dev_get_drvdata(dev); + struct csi_state *state =3D mipi_sd_to_csi2_state(sd); + + if (!(state->state & ST_SUSPENDED)) + return 0; + + return imx8mq_mipi_csi_pm_resume(dev); } =20 static int __maybe_unused imx8mq_mipi_csi_runtime_suspend(struct device *d= ev) { - return imx8mq_mipi_csi_pm_suspend(dev, true); + struct v4l2_subdev *sd =3D dev_get_drvdata(dev); + struct csi_state *state =3D mipi_sd_to_csi2_state(sd); + int ret; + + ret =3D imx8mq_mipi_csi_pm_suspend(dev); + if (ret) + return ret; + + ret =3D icc_set_bw(state->icc_path, 0, 0); + if (ret) + dev_err(dev, "icc_set_bw failed with %d\n", ret); + + return ret; } =20 static int __maybe_unused imx8mq_mipi_csi_runtime_resume(struct device *de= v) { - return imx8mq_mipi_csi_pm_resume(dev, true); + struct v4l2_subdev *sd =3D dev_get_drvdata(dev); + struct csi_state *state =3D mipi_sd_to_csi2_state(sd); + int ret; + + ret =3D icc_set_bw(state->icc_path, 0, state->icc_path_bw); + if (ret) { + dev_err(dev, "icc_set_bw failed with %d\n", ret); + return ret; + } + + return imx8mq_mipi_csi_pm_resume(dev); } =20 static const struct dev_pm_ops imx8mq_mipi_csi_pm_ops =3D { @@ -921,7 +941,7 @@ static int imx8mq_mipi_csi_probe(struct platform_device= *pdev) /* Enable runtime PM. */ pm_runtime_enable(dev); if (!pm_runtime_enabled(dev)) { - ret =3D imx8mq_mipi_csi_pm_resume(dev, true); + ret =3D imx8mq_mipi_csi_runtime_resume(dev); if (ret < 0) goto icc; } @@ -934,7 +954,7 @@ static int imx8mq_mipi_csi_probe(struct platform_device= *pdev) =20 cleanup: pm_runtime_disable(&pdev->dev); - imx8mq_mipi_csi_pm_suspend(&pdev->dev, true); + imx8mq_mipi_csi_runtime_suspend(&pdev->dev); =20 media_entity_cleanup(&state->sd.entity); v4l2_async_nf_unregister(&state->notifier); @@ -958,7 +978,7 @@ static int imx8mq_mipi_csi_remove(struct platform_devic= e *pdev) v4l2_async_unregister_subdev(&state->sd); =20 pm_runtime_disable(&pdev->dev); - imx8mq_mipi_csi_pm_suspend(&pdev->dev, true); + imx8mq_mipi_csi_runtime_suspend(&pdev->dev); media_entity_cleanup(&state->sd.entity); mutex_destroy(&state->lock); pm_runtime_set_suspended(&pdev->dev); diff --git a/drivers/staging/media/meson/vdec/esparser.c b/drivers/staging/= media/meson/vdec/esparser.c index db7022707ff8..86ccc8937afc 100644 --- a/drivers/staging/media/meson/vdec/esparser.c +++ b/drivers/staging/media/meson/vdec/esparser.c @@ -328,7 +328,12 @@ esparser_queue(struct amvdec_session *sess, struct vb2= _v4l2_buffer *vbuf) =20 offset =3D esparser_get_offset(sess); =20 - amvdec_add_ts(sess, vb->timestamp, vbuf->timecode, offset, vbuf->flags); + ret =3D amvdec_add_ts(sess, vb->timestamp, vbuf->timecode, offset, vbuf->= flags); + if (ret) { + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); + return ret; + } + dev_dbg(core->dev, "esparser: ts =3D %llu pld_size =3D %u offset =3D %08X= flags =3D %08X\n", vb->timestamp, payload_size, offset, vbuf->flags); =20 diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.c b/drivers/stag= ing/media/meson/vdec/vdec_helpers.c index b9125c295d1d..06fd66539797 100644 --- a/drivers/staging/media/meson/vdec/vdec_helpers.c +++ b/drivers/staging/media/meson/vdec/vdec_helpers.c @@ -227,13 +227,16 @@ int amvdec_set_canvases(struct amvdec_session *sess, } EXPORT_SYMBOL_GPL(amvdec_set_canvases); =20 -void amvdec_add_ts(struct amvdec_session *sess, u64 ts, - struct v4l2_timecode tc, u32 offset, u32 vbuf_flags) +int amvdec_add_ts(struct amvdec_session *sess, u64 ts, + struct v4l2_timecode tc, u32 offset, u32 vbuf_flags) { struct amvdec_timestamp *new_ts; unsigned long flags; =20 new_ts =3D kzalloc(sizeof(*new_ts), GFP_KERNEL); + if (!new_ts) + return -ENOMEM; + new_ts->ts =3D ts; new_ts->tc =3D tc; new_ts->offset =3D offset; @@ -242,6 +245,7 @@ void amvdec_add_ts(struct amvdec_session *sess, u64 ts, spin_lock_irqsave(&sess->ts_spinlock, flags); list_add_tail(&new_ts->list, &sess->timestamps); spin_unlock_irqrestore(&sess->ts_spinlock, flags); + return 0; } EXPORT_SYMBOL_GPL(amvdec_add_ts); =20 diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.h b/drivers/stag= ing/media/meson/vdec/vdec_helpers.h index 88137d15aa3a..4bf3e61d081b 100644 --- a/drivers/staging/media/meson/vdec/vdec_helpers.h +++ b/drivers/staging/media/meson/vdec/vdec_helpers.h @@ -56,8 +56,8 @@ void amvdec_dst_buf_done_offset(struct amvdec_session *se= ss, * @offset: offset in the VIFIFO where the associated packet was written * @flags: the vb2_v4l2_buffer flags */ -void amvdec_add_ts(struct amvdec_session *sess, u64 ts, - struct v4l2_timecode tc, u32 offset, u32 flags); +int amvdec_add_ts(struct amvdec_session *sess, u64 ts, + struct v4l2_timecode tc, u32 offset, u32 flags); void amvdec_remove_ts(struct amvdec_session *sess, u64 ts); =20 /** diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/sta= ging/media/sunxi/cedrus/cedrus_h264.c index b4173a8926d6..d8fb93035470 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c @@ -38,7 +38,7 @@ struct cedrus_h264_sram_ref_pic { =20 #define CEDRUS_H264_FRAME_NUM 18 =20 -#define CEDRUS_NEIGHBOR_INFO_BUF_SIZE (16 * SZ_1K) +#define CEDRUS_NEIGHBOR_INFO_BUF_SIZE (32 * SZ_1K) #define CEDRUS_MIN_PIC_INFO_BUF_SIZE (130 * SZ_1K) =20 static void cedrus_h264_write_sram(struct cedrus_dev *dev, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/sta= ging/media/sunxi/cedrus/cedrus_h265.c index 8829a7bab07e..ffade5cbd2e4 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c @@ -23,7 +23,7 @@ * Subsequent BSP implementations seem to double the neighbor info buffer = size * for the H6 SoC, which may be related to 10 bit H265 support. */ -#define CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE (397 * SZ_1K) +#define CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE (794 * SZ_1K) #define CEDRUS_H265_ENTRY_POINTS_BUF_SIZE (4 * SZ_1K) #define CEDRUS_H265_MV_COL_BUF_UNIT_CTB_SIZE 160 =20 diff --git a/drivers/staging/media/zoran/zoran.h b/drivers/staging/media/zo= ran/zoran.h index b1ad2a2b914c..50d5a7acfab6 100644 --- a/drivers/staging/media/zoran/zoran.h +++ b/drivers/staging/media/zoran/zoran.h @@ -313,6 +313,6 @@ static inline struct zoran *to_zoran(struct v4l2_device= *v4l2_dev) =20 #endif =20 -int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq); +int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir); void zoran_queue_exit(struct zoran *zr); int zr_set_buf(struct zoran *zr); diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/staging/med= ia/zoran/zoran_card.c index f259585b0689..11d415c0c05d 100644 --- a/drivers/staging/media/zoran/zoran_card.c +++ b/drivers/staging/media/zoran/zoran_card.c @@ -803,6 +803,52 @@ int zoran_check_jpg_settings(struct zoran *zr, return 0; } =20 +static int zoran_init_video_device(struct zoran *zr, struct video_device *= video_dev, int dir) +{ + int err; + + /* Now add the template and register the device unit. */ + *video_dev =3D zoran_template; + video_dev->v4l2_dev =3D &zr->v4l2_dev; + video_dev->lock =3D &zr->lock; + video_dev->device_caps =3D V4L2_CAP_STREAMING | V4L2_CAP_READWRITE | dir; + + strscpy(video_dev->name, ZR_DEVNAME(zr), sizeof(video_dev->name)); + /* + * It's not a mem2mem device, but you can both capture and output from on= e and the same + * device. This should really be split up into two device nodes, but that= 's a job for + * another day. + */ + video_dev->vfl_dir =3D VFL_DIR_M2M; + zoran_queue_init(zr, &zr->vq, V4L2_BUF_TYPE_VIDEO_CAPTURE); + + err =3D video_register_device(video_dev, VFL_TYPE_VIDEO, video_nr[zr->id]= ); + if (err < 0) + return err; + video_set_drvdata(video_dev, zr); + return 0; +} + +static void zoran_exit_video_devices(struct zoran *zr) +{ + video_unregister_device(zr->video_dev); + kfree(zr->video_dev); +} + +static int zoran_init_video_devices(struct zoran *zr) +{ + int err; + + zr->video_dev =3D video_device_alloc(); + if (!zr->video_dev) + return -ENOMEM; + + err =3D zoran_init_video_device(zr, zr->video_dev, V4L2_CAP_VIDEO_CAPTURE= ); + if (err) + kfree(zr->video_dev); + return err; +} + void zoran_open_init_params(struct zoran *zr) { int i; @@ -874,17 +920,11 @@ static int zr36057_init(struct zoran *zr) zoran_open_init_params(zr); =20 /* allocate memory *before* doing anything to the hardware in case alloca= tion fails */ - zr->video_dev =3D video_device_alloc(); - if (!zr->video_dev) { - err =3D -ENOMEM; - goto exit; - } zr->stat_com =3D dma_alloc_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32), &zr->p_sc, GFP_KERNEL); if (!zr->stat_com) { - err =3D -ENOMEM; - goto exit_video; + return -ENOMEM; } for (j =3D 0; j < BUZ_NUM_STAT_COM; j++) zr->stat_com[j] =3D cpu_to_le32(1); /* mark as unavailable to zr36057 */ @@ -897,26 +937,9 @@ static int zr36057_init(struct zoran *zr) goto exit_statcom; } =20 - /* Now add the template and register the device unit. */ - *zr->video_dev =3D zoran_template; - zr->video_dev->v4l2_dev =3D &zr->v4l2_dev; - zr->video_dev->lock =3D &zr->lock; - zr->video_dev->device_caps =3D V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTUR= E; - - strscpy(zr->video_dev->name, ZR_DEVNAME(zr), sizeof(zr->video_dev->name)); - /* - * It's not a mem2mem device, but you can both capture and output from on= e and the same - * device. This should really be split up into two device nodes, but that= 's a job for - * another day. - */ - zr->video_dev->vfl_dir =3D VFL_DIR_M2M; - - zoran_queue_init(zr, &zr->vq); - - err =3D video_register_device(zr->video_dev, VFL_TYPE_VIDEO, video_nr[zr-= >id]); - if (err < 0) + err =3D zoran_init_video_devices(zr); + if (err) goto exit_statcomb; - video_set_drvdata(zr->video_dev, zr); =20 zoran_init_hardware(zr); if (!pass_through) { @@ -931,9 +954,6 @@ static int zr36057_init(struct zoran *zr) dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32) * 2, = zr->stat_comb, zr->p_scb); exit_statcom: dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32), zr->= stat_com, zr->p_sc); -exit_video: - kfree(zr->video_dev); -exit: return err; } =20 @@ -965,7 +985,7 @@ static void zoran_remove(struct pci_dev *pdev) dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32) * 2, = zr->stat_comb, zr->p_scb); pci_release_regions(pdev); pci_disable_device(zr->pci_dev); - video_unregister_device(zr->video_dev); + zoran_exit_video_devices(zr); exit_free: v4l2_ctrl_handler_free(&zr->hdl); v4l2_device_unregister(&zr->v4l2_dev); @@ -1069,8 +1089,10 @@ static int zoran_probe(struct pci_dev *pdev, const s= truct pci_device_id *ent) =20 err =3D dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (err) - return -ENODEV; - vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); + return err; + err =3D vb2_dma_contig_set_max_seg_size(&pdev->dev, U32_MAX); + if (err) + return err; =20 nr =3D zoran_num++; if (nr >=3D BUZ_MAX) { diff --git a/drivers/staging/media/zoran/zoran_device.c b/drivers/staging/m= edia/zoran/zoran_device.c index 5b12a730a229..fb1f0465ca87 100644 --- a/drivers/staging/media/zoran/zoran_device.c +++ b/drivers/staging/media/zoran/zoran_device.c @@ -814,7 +814,7 @@ static void zoran_reap_stat_com(struct zoran *zr) if (zr->jpg_settings.tmp_dcm =3D=3D 1) i =3D (zr->jpg_dma_tail - zr->jpg_err_shift) & BUZ_MASK_STAT_COM; else - i =3D ((zr->jpg_dma_tail - zr->jpg_err_shift) & 1) * 2 + 1; + i =3D ((zr->jpg_dma_tail - zr->jpg_err_shift) & 1) * 2; =20 stat_com =3D le32_to_cpu(zr->stat_com[i]); if ((stat_com & 1) =3D=3D 0) { @@ -826,6 +826,11 @@ static void zoran_reap_stat_com(struct zoran *zr) size =3D (stat_com & GENMASK(22, 1)) >> 1; =20 buf =3D zr->inuse[i]; + if (!buf) { + spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); + pci_err(zr->pci_dev, "No buffer at slot %d\n", i); + return; + } buf->vbuf.vb2_buf.timestamp =3D ktime_get_ns(); =20 if (zr->codec_mode =3D=3D BUZ_MODE_MOTION_COMPRESS) { diff --git a/drivers/staging/media/zoran/zoran_driver.c b/drivers/staging/m= edia/zoran/zoran_driver.c index 46382e43f1bf..84665637ebb7 100644 --- a/drivers/staging/media/zoran/zoran_driver.c +++ b/drivers/staging/media/zoran/zoran_driver.c @@ -255,8 +255,6 @@ static int zoran_querycap(struct file *file, void *__fh= , struct v4l2_capability strscpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)); strscpy(cap->driver, "zoran", sizeof(cap->driver)); snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(zr->pci= _dev)); - cap->device_caps =3D zr->video_dev->device_caps; - cap->capabilities =3D cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } =20 @@ -582,6 +580,9 @@ static int zoran_s_std(struct file *file, void *__fh, v= 4l2_std_id std) struct zoran *zr =3D video_drvdata(file); int res =3D 0; =20 + if (zr->norm =3D=3D std) + return 0; + if (zr->running !=3D ZORAN_MAP_MODE_NONE) return -EBUSY; =20 @@ -739,6 +740,7 @@ static int zoran_g_parm(struct file *file, void *priv, = struct v4l2_streamparm *p if (parm->type !=3D V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; =20 + parm->parm.capture.readbuffers =3D 9; return 0; } =20 @@ -869,6 +871,10 @@ int zr_set_buf(struct zoran *zr) vbuf =3D &buf->vbuf; =20 buf->vbuf.field =3D V4L2_FIELD_INTERLACED; + if (BUZ_MAX_HEIGHT < (zr->v4l_settings.height * 2)) + buf->vbuf.field =3D V4L2_FIELD_INTERLACED; + else + buf->vbuf.field =3D V4L2_FIELD_TOP; vb2_set_plane_payload(&buf->vbuf.vb2_buf, 0, zr->buffer_size); vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_DONE); zr->inuse[0] =3D NULL; @@ -928,6 +934,7 @@ static int zr_vb2_start_streaming(struct vb2_queue *vq,= unsigned int count) zr->stat_com[j] =3D cpu_to_le32(1); zr->inuse[j] =3D NULL; } + zr->vbseq =3D 0; =20 if (zr->map_mode !=3D ZORAN_MAP_MODE_RAW) { pci_info(zr->pci_dev, "START JPG\n"); @@ -1008,7 +1015,7 @@ static const struct vb2_ops zr_video_qops =3D { .wait_finish =3D vb2_ops_wait_finish, }; =20 -int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq) +int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir) { int err; =20 @@ -1016,8 +1023,9 @@ int zoran_queue_init(struct zoran *zr, struct vb2_que= ue *vq) INIT_LIST_HEAD(&zr->queued_bufs); =20 vq->dev =3D &zr->pci_dev->dev; - vq->type =3D V4L2_BUF_TYPE_VIDEO_CAPTURE; - vq->io_modes =3D VB2_USERPTR | VB2_DMABUF | VB2_MMAP | VB2_READ | VB2_WRI= TE; + vq->type =3D dir; + + vq->io_modes =3D VB2_DMABUF | VB2_MMAP | VB2_READ | VB2_WRITE; vq->drv_priv =3D zr; vq->buf_struct_size =3D sizeof(struct zr_buffer); vq->ops =3D &zr_video_qops; diff --git a/drivers/staging/mt7621-dts/gbpc1.dts b/drivers/staging/mt7621-= dts/gbpc1.dts index e38a083811e5..5ae94b1ad599 100644 --- a/drivers/staging/mt7621-dts/gbpc1.dts +++ b/drivers/staging/mt7621-dts/gbpc1.dts @@ -12,7 +12,8 @@ / { =20 memory@0 { device_type =3D "memory"; - reg =3D <0x0 0x1c000000>, <0x20000000 0x4000000>; + reg =3D <0x00000000 0x1c000000>, + <0x20000000 0x04000000>; }; =20 chosen { @@ -38,24 +39,16 @@ reset { gpio-leds { compatible =3D "gpio-leds"; =20 - system { - label =3D "gb-pc1:green:system"; + power { + label =3D "green:power"; gpios =3D <&gpio 6 GPIO_ACTIVE_LOW>; + linux,default-trigger =3D "default-on"; }; =20 - status { - label =3D "gb-pc1:green:status"; + system { + label =3D "green:system"; gpios =3D <&gpio 8 GPIO_ACTIVE_LOW>; - }; - - lan1 { - label =3D "gb-pc1:green:lan1"; - gpios =3D <&gpio 24 GPIO_ACTIVE_LOW>; - }; - - lan2 { - label =3D "gb-pc1:green:lan2"; - gpios =3D <&gpio 25 GPIO_ACTIVE_LOW>; + linux,default-trigger =3D "disk-activity"; }; }; }; @@ -95,9 +88,8 @@ factory: partition@40000 { =20 partition@50000 { label =3D "firmware"; - reg =3D <0x50000 0x1FB0000>; + reg =3D <0x50000 0x1fb0000>; }; - }; }; =20 @@ -106,9 +98,12 @@ &pcie { }; =20 &pinctrl { - state_default: pinctrl0 { - default_gpio: gpio { - groups =3D "wdt", "rgmii2", "uart3"; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&state_default>; + + state_default: state-default { + gpio-pinmux { + groups =3D "rgmii2", "uart3", "wdt"; function =3D "gpio"; }; }; @@ -117,12 +112,13 @@ default_gpio: gpio { &switch0 { ports { port@0 { + status =3D "okay"; label =3D "ethblack"; - status =3D "ok"; }; + port@4 { + status =3D "okay"; label =3D "ethblue"; - status =3D "ok"; }; }; }; diff --git a/drivers/staging/mt7621-dts/gbpc2.dts b/drivers/staging/mt7621-= dts/gbpc2.dts index 6fe603c7711d..a7fce8de6147 100644 --- a/drivers/staging/mt7621-dts/gbpc2.dts +++ b/drivers/staging/mt7621-dts/gbpc2.dts @@ -1,22 +1,122 @@ // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) /dts-v1/; =20 -#include "gbpc1.dts" +#include "mt7621.dtsi" + +#include +#include =20 / { compatible =3D "gnubee,gb-pc2", "mediatek,mt7621-soc"; model =3D "GB-PC2"; + + memory@0 { + device_type =3D "memory"; + reg =3D <0x00000000 0x1c000000>, + <0x20000000 0x04000000>; + }; + + chosen { + bootargs =3D "console=3DttyS0,57600"; + }; + + palmbus: palmbus@1e000000 { + i2c@900 { + status =3D "okay"; + }; + }; + + gpio-keys { + compatible =3D "gpio-keys"; + + reset { + label =3D "reset"; + gpios =3D <&gpio 18 GPIO_ACTIVE_HIGH>; + linux,code =3D ; + }; + }; +}; + +&sdhci { + status =3D "okay"; +}; + +&spi0 { + status =3D "okay"; + + m25p80@0 { + #address-cells =3D <1>; + #size-cells =3D <1>; + compatible =3D "jedec,spi-nor"; + reg =3D <0>; + spi-max-frequency =3D <50000000>; + broken-flash-reset; + + partition@0 { + label =3D "u-boot"; + reg =3D <0x0 0x30000>; + read-only; + }; + + partition@30000 { + label =3D "u-boot-env"; + reg =3D <0x30000 0x10000>; + read-only; + }; + + factory: partition@40000 { + label =3D "factory"; + reg =3D <0x40000 0x10000>; + read-only; + }; + + partition@50000 { + label =3D "firmware"; + reg =3D <0x50000 0x1fb0000>; + }; + }; }; =20 -&default_gpio { - groups =3D "wdt", "uart3"; - function =3D "gpio"; +&pcie { + status =3D "okay"; }; =20 -&gmac1 { - status =3D "ok"; +&pinctrl { + pinctrl-names =3D "default"; + pinctrl-0 =3D <&state_default>; + + state_default: state-default { + gpio-pinmux { + groups =3D "wdt"; + function =3D "gpio"; + }; + }; }; =20 -&phy_external { - status =3D "ok"; +ðernet { + gmac1: mac@1 { + status =3D "okay"; + phy-handle =3D <ðphy7>; + }; + + mdio-bus { + ethphy7: ethernet-phy@7 { + reg =3D <7>; + phy-mode =3D "rgmii-rxid"; + }; + }; +}; + +&switch0 { + ports { + port@0 { + status =3D "okay"; + label =3D "ethblack"; + }; + + port@4 { + status =3D "okay"; + label =3D "ethblue"; + }; + }; }; diff --git a/drivers/staging/mt7621-dts/mt7621.dtsi b/drivers/staging/mt762= 1-dts/mt7621.dtsi index 6d158e4f4b8c..263ef53e1e92 100644 --- a/drivers/staging/mt7621-dts/mt7621.dtsi +++ b/drivers/staging/mt7621-dts/mt7621.dtsi @@ -44,9 +44,9 @@ mmc_fixed_3v3: fixedregulator@0 { regulator-max-microvolt =3D <3300000>; enable-active-high; regulator-always-on; - }; + }; =20 - mmc_fixed_1v8_io: fixedregulator@1 { + mmc_fixed_1v8_io: fixedregulator@1 { compatible =3D "regulator-fixed"; regulator-name =3D "mmc_io"; regulator-min-microvolt =3D <1800000>; @@ -363,37 +363,32 @@ ethernet: ethernet@1e100000 { =20 mediatek,ethsys =3D <&sysc>; =20 + pinctrl-names =3D "default"; + pinctrl-0 =3D <&mdio_pins>, <&rgmii1_pins>, <&rgmii2_pins>; =20 gmac0: mac@0 { compatible =3D "mediatek,eth-mac"; reg =3D <0>; phy-mode =3D "rgmii"; + fixed-link { speed =3D <1000>; full-duplex; pause; }; }; + gmac1: mac@1 { compatible =3D "mediatek,eth-mac"; reg =3D <1>; status =3D "off"; phy-mode =3D "rgmii-rxid"; - phy-handle =3D <&phy_external>; }; + mdio-bus { #address-cells =3D <1>; #size-cells =3D <0>; =20 - phy_external: ethernet-phy@5 { - status =3D "off"; - reg =3D <5>; - phy-mode =3D "rgmii-rxid"; - - pinctrl-names =3D "default"; - pinctrl-0 =3D <&rgmii2_pins>; - }; - switch0: switch0@0 { compatible =3D "mediatek,mt7621"; #address-cells =3D <1>; @@ -411,36 +406,43 @@ ports { #address-cells =3D <1>; #size-cells =3D <0>; reg =3D <0>; + port@0 { status =3D "off"; reg =3D <0>; label =3D "lan0"; }; + port@1 { status =3D "off"; reg =3D <1>; label =3D "lan1"; }; + port@2 { status =3D "off"; reg =3D <2>; label =3D "lan2"; }; + port@3 { status =3D "off"; reg =3D <3>; label =3D "lan3"; }; + port@4 { status =3D "off"; reg =3D <4>; label =3D "lan4"; }; + port@6 { reg =3D <6>; label =3D "cpu"; ethernet =3D <&gmac0>; phy-mode =3D "trgmii"; + fixed-link { speed =3D <1000>; full-duplex; diff --git a/drivers/staging/qlge/qlge_main.c b/drivers/staging/qlge/qlge_m= ain.c index 9873bb2a9ee4..113a3efd12e9 100644 --- a/drivers/staging/qlge/qlge_main.c +++ b/drivers/staging/qlge/qlge_main.c @@ -4605,14 +4605,12 @@ static int qlge_probe(struct pci_dev *pdev, err =3D register_netdev(ndev); if (err) { dev_err(&pdev->dev, "net device registration failed.\n"); - qlge_release_all(pdev); - pci_disable_device(pdev); - goto netdev_free; + goto cleanup_pdev; } =20 err =3D qlge_health_create_reporters(qdev); if (err) - goto netdev_free; + goto unregister_netdev; =20 /* Start up the timer to trigger EEH if * the bus goes dead @@ -4626,6 +4624,11 @@ static int qlge_probe(struct pci_dev *pdev, devlink_register(devlink); return 0; =20 +unregister_netdev: + unregister_netdev(ndev); +cleanup_pdev: + qlge_release_all(pdev); + pci_disable_device(pdev); netdev_free: free_netdev(ndev); devlink_free: diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r818= 8eu/core/rtw_recv.c index 51a13262a226..d120d61454a3 100644 --- a/drivers/staging/r8188eu/core/rtw_recv.c +++ b/drivers/staging/r8188eu/core/rtw_recv.c @@ -1853,8 +1853,7 @@ static int recv_func(struct adapter *padapter, struct= recv_frame *rframe) struct recv_frame *pending_frame; int cnt =3D 0; =20 - pending_frame =3D rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pendi= ng_queue); - while (pending_frame) { + while ((pending_frame =3D rtw_alloc_recvframe(&padapter->recvpriv.uc_swd= ec_pending_queue))) { cnt++; recv_func_posthandle(padapter, pending_frame); } diff --git a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c b/drivers/stag= ing/r8188eu/hal/rtl8188e_hal_init.c index 8c00f2dd67da..8656d4061059 100644 --- a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c @@ -540,10 +540,10 @@ static int load_firmware(struct rt_firmware *pFirmwar= e, struct device *device) } memcpy(pFirmware->szFwBuffer, fw->data, fw->size); pFirmware->ulFwLength =3D fw->size; - release_firmware(fw); - DBG_88E_LEVEL(_drv_info_, "+%s: !bUsedWoWLANFw, FmrmwareLen:%d+\n", __fun= c__, pFirmware->ulFwLength); + dev_dbg(device, "!bUsedWoWLANFw, FmrmwareLen:%d+\n", pFirmware->ulFwLengt= h); =20 Exit: + release_firmware(fw); return rtStatus; } =20 diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/driv= ers/thermal/intel/int340x_thermal/int3400_thermal.c index 68f61a738930..f232a53329e1 100644 --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c @@ -53,7 +53,7 @@ struct int3400_thermal_priv { struct art *arts; int trt_count; struct trt *trts; - u8 uuid_bitmap; + u32 uuid_bitmap; int rel_misc_dev_res; int current_uuid_index; char *data_vault; @@ -468,6 +468,11 @@ static void int3400_setup_gddv(struct int3400_thermal_= priv *priv) priv->data_vault =3D kmemdup(obj->package.elements[0].buffer.pointer, obj->package.elements[0].buffer.length, GFP_KERNEL); + if (!priv->data_vault) { + kfree(buffer.pointer); + return; + } + bin_attr_data_vault.private =3D priv->data_vault; bin_attr_data_vault.size =3D obj->package.elements[0].buffer.length; kfree(buffer.pointer); diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c index 82a76cac94de..32366caca662 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c @@ -1417,7 +1417,9 @@ static int __init hvc_iucv_init(void) */ static int __init hvc_iucv_config(char *val) { - return kstrtoul(val, 10, &hvc_iucv_devices); + if (kstrtoul(val, 10, &hvc_iucv_devices)) + pr_warn("hvc_iucv=3D invalid parameter value '%s'\n", val); + return 1; } =20 =20 diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 39458b42df7b..88d2f16fbf89 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -719,6 +719,7 @@ static int mxser_activate(struct tty_port *port, struct= tty_struct *tty) struct mxser_port *info =3D container_of(port, struct mxser_port, port); unsigned long page; unsigned long flags; + int ret; =20 page =3D __get_free_page(GFP_KERNEL); if (!page) @@ -728,9 +729,9 @@ static int mxser_activate(struct tty_port *port, struct= tty_struct *tty) =20 if (!info->type) { set_bit(TTY_IO_ERROR, &tty->flags); - free_page(page); spin_unlock_irqrestore(&info->slock, flags); - return 0; + ret =3D 0; + goto err_free_xmit; } info->port.xmit_buf =3D (unsigned char *) page; =20 @@ -750,8 +751,10 @@ static int mxser_activate(struct tty_port *port, struc= t tty_struct *tty) if (capable(CAP_SYS_ADMIN)) { set_bit(TTY_IO_ERROR, &tty->flags); return 0; - } else - return -ENODEV; + } + + ret =3D -ENODEV; + goto err_free_xmit; } =20 /* @@ -796,6 +799,10 @@ static int mxser_activate(struct tty_port *port, struc= t tty_struct *tty) spin_unlock_irqrestore(&info->slock, flags); =20 return 0; +err_free_xmit: + free_page(page); + info->port.xmit_buf =3D NULL; + return ret; } =20 /* diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/seri= al/8250/8250_aspeed_vuart.c index 2350fb3bb5e4..c2cecc6f47db 100644 --- a/drivers/tty/serial/8250/8250_aspeed_vuart.c +++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c @@ -487,7 +487,7 @@ static int aspeed_vuart_probe(struct platform_device *p= dev) port.port.irq =3D irq_of_parse_and_map(np, 0); port.port.handle_irq =3D aspeed_vuart_handle_irq; port.port.iotype =3D UPIO_MEM; - port.port.type =3D PORT_16550A; + port.port.type =3D PORT_ASPEED_VUART; port.port.uartclk =3D clk; port.port.flags =3D UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_NO_THRE_TEST; diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8= 250_dma.c index 890fa7ddaa7f..b3c3f7e5851a 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -64,10 +64,19 @@ int serial8250_tx_dma(struct uart_8250_port *p) struct uart_8250_dma *dma =3D p->dma; struct circ_buf *xmit =3D &p->port.state->xmit; struct dma_async_tx_descriptor *desc; + struct uart_port *up =3D &p->port; int ret; =20 - if (dma->tx_running) + if (dma->tx_running) { + if (up->x_char) { + dmaengine_pause(dma->txchan); + uart_xchar_out(up, UART_TX); + dmaengine_resume(dma->txchan); + } return 0; + } else if (up->x_char) { + uart_xchar_out(up, UART_TX); + } =20 if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) { /* We have been called from __dma_tx_complete() */ diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/= 8250_lpss.c index d3bafec7619d..0f5af061e0b4 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -117,8 +117,7 @@ static int byt_serial_setup(struct lpss8250 *lpss, stru= ct uart_port *port) { struct dw_dma_slave *param =3D &lpss->dma_param; struct pci_dev *pdev =3D to_pci_dev(port->dev); - unsigned int dma_devfn =3D PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); - struct pci_dev *dma_dev =3D pci_get_slot(pdev->bus, dma_devfn); + struct pci_dev *dma_dev; =20 switch (pdev->device) { case PCI_DEVICE_ID_INTEL_BYT_UART1: @@ -137,6 +136,8 @@ static int byt_serial_setup(struct lpss8250 *lpss, stru= ct uart_port *port) return -EINVAL; } =20 + dma_dev =3D pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 0)); + param->dma_dev =3D &dma_dev->dev; param->m_master =3D 0; param->p_master =3D 1; @@ -152,6 +153,14 @@ static int byt_serial_setup(struct lpss8250 *lpss, str= uct uart_port *port) return 0; } =20 +static void byt_serial_exit(struct lpss8250 *lpss) +{ + struct dw_dma_slave *param =3D &lpss->dma_param; + + /* Paired with pci_get_slot() in the byt_serial_setup() above */ + put_device(param->dma_dev); +} + static int ehl_serial_setup(struct lpss8250 *lpss, struct uart_port *port) { struct uart_8250_dma *dma =3D &lpss->data.dma; @@ -170,6 +179,13 @@ static int ehl_serial_setup(struct lpss8250 *lpss, str= uct uart_port *port) return 0; } =20 +static void ehl_serial_exit(struct lpss8250 *lpss) +{ + struct uart_8250_port *up =3D serial8250_get_port(lpss->data.line); + + up->dma =3D NULL; +} + #ifdef CONFIG_SERIAL_8250_DMA static const struct dw_dma_platform_data qrk_serial_dma_pdata =3D { .nr_channels =3D 2, @@ -344,8 +360,7 @@ static int lpss8250_probe(struct pci_dev *pdev, const s= truct pci_device_id *id) return 0; =20 err_exit: - if (lpss->board->exit) - lpss->board->exit(lpss); + lpss->board->exit(lpss); pci_free_irq_vectors(pdev); return ret; } @@ -356,8 +371,7 @@ static void lpss8250_remove(struct pci_dev *pdev) =20 serial8250_unregister_port(lpss->data.line); =20 - if (lpss->board->exit) - lpss->board->exit(lpss); + lpss->board->exit(lpss); pci_free_irq_vectors(pdev); } =20 @@ -365,12 +379,14 @@ static const struct lpss8250_board byt_board =3D { .freq =3D 100000000, .base_baud =3D 2764800, .setup =3D byt_serial_setup, + .exit =3D byt_serial_exit, }; =20 static const struct lpss8250_board ehl_board =3D { .freq =3D 200000000, .base_baud =3D 12500000, .setup =3D ehl_serial_setup, + .exit =3D ehl_serial_exit, }; =20 static const struct lpss8250_board qrk_board =3D { diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8= 250_mid.c index efa0515139f8..e6c1791609dd 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -73,6 +73,11 @@ static int pnw_setup(struct mid8250 *mid, struct uart_po= rt *p) return 0; } =20 +static void pnw_exit(struct mid8250 *mid) +{ + pci_dev_put(mid->dma_dev); +} + static int tng_handle_irq(struct uart_port *p) { struct mid8250 *mid =3D p->private_data; @@ -124,6 +129,11 @@ static int tng_setup(struct mid8250 *mid, struct uart_= port *p) return 0; } =20 +static void tng_exit(struct mid8250 *mid) +{ + pci_dev_put(mid->dma_dev); +} + static int dnv_handle_irq(struct uart_port *p) { struct mid8250 *mid =3D p->private_data; @@ -330,9 +340,9 @@ static int mid8250_probe(struct pci_dev *pdev, const st= ruct pci_device_id *id) =20 pci_set_drvdata(pdev, mid); return 0; + err: - if (mid->board->exit) - mid->board->exit(mid); + mid->board->exit(mid); return ret; } =20 @@ -342,8 +352,7 @@ static void mid8250_remove(struct pci_dev *pdev) =20 serial8250_unregister_port(mid->line); =20 - if (mid->board->exit) - mid->board->exit(mid); + mid->board->exit(mid); } =20 static const struct mid8250_board pnw_board =3D { @@ -351,6 +360,7 @@ static const struct mid8250_board pnw_board =3D { .freq =3D 50000000, .base_baud =3D 115200, .setup =3D pnw_setup, + .exit =3D pnw_exit, }; =20 static const struct mid8250_board tng_board =3D { @@ -358,6 +368,7 @@ static const struct mid8250_board tng_board =3D { .freq =3D 38400000, .base_baud =3D 1843200, .setup =3D tng_setup, + .exit =3D tng_exit, }; =20 static const struct mid8250_board dnv_board =3D { diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/= 8250_port.c index 46e2079ad1aa..1e1750a9614e 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -307,6 +307,14 @@ static const struct serial8250_config uart_config[] = =3D { .rxtrig_bytes =3D {1, 32, 64, 112}, .flags =3D UART_CAP_FIFO | UART_CAP_SLEEP, }, + [PORT_ASPEED_VUART] =3D { + .name =3D "ASPEED VUART", + .fifo_size =3D 16, + .tx_loadsz =3D 16, + .fcr =3D UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, + .rxtrig_bytes =3D {1, 4, 8, 14}, + .flags =3D UART_CAP_FIFO, + }, }; =20 /* Uart divisor latch read */ @@ -1615,6 +1623,18 @@ static inline void start_tx_rs485(struct uart_port *= port) struct uart_8250_port *up =3D up_to_u8250p(port); struct uart_8250_em485 *em485 =3D up->em485; =20 + /* + * While serial8250_em485_handle_stop_tx() is a noop if + * em485->active_timer !=3D &em485->stop_tx_timer, it might happen that + * the timer is still armed and triggers only after the current bunch of + * chars is send and em485->active_timer =3D=3D &em485->stop_tx_timer aga= in. + * So cancel the timer. There is still a theoretical race condition if + * the timer is already running and only comes around to check for + * em485->active_timer when &em485->stop_tx_timer is armed again. + */ + if (em485->active_timer =3D=3D &em485->stop_tx_timer) + hrtimer_try_to_cancel(&em485->stop_tx_timer); + em485->active_timer =3D NULL; =20 if (em485->tx_stopped) { @@ -1799,9 +1819,7 @@ void serial8250_tx_chars(struct uart_8250_port *up) int count; =20 if (port->x_char) { - serial_out(up, UART_TX, port->x_char); - port->icount.tx++; - port->x_char =3D 0; + uart_xchar_out(port, UART_TX); return; } if (uart_tx_stopped(port)) { diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index 49d0c7f2b29b..79b7db8580e0 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -403,16 +403,16 @@ static int kgdboc_option_setup(char *opt) { if (!opt) { pr_err("config string not provided\n"); - return -EINVAL; + return 1; } =20 if (strlen(opt) >=3D MAX_CONFIG_LEN) { pr_err("config string too long\n"); - return -ENOSPC; + return 1; } strcpy(config, opt); =20 - return 0; + return 1; } =20 __setup("kgdboc=3D", kgdboc_option_setup); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_c= ore.c index dc6129ddef85..eb15423f935a 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -652,6 +652,20 @@ static void uart_flush_buffer(struct tty_struct *tty) tty_port_tty_wakeup(&state->port); } =20 +/* + * This function performs low-level write of high-priority XON/XOFF + * character and accounting for it. + * + * Requires uart_port to implement .serial_out(). + */ +void uart_xchar_out(struct uart_port *uport, int offset) +{ + serial_port_out(uport, offset, uport->x_char); + uport->icount.tx++; + uport->x_char =3D 0; +} +EXPORT_SYMBOL_GPL(uart_xchar_out); + /* * This function is used to send a high-priority XON/XOFF character to * the device diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index df3522dab31b..1e7dc130c39a 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -762,7 +762,7 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci) } pm_runtime_allow(xhci_to_hcd(xhci)->self.controller); xhci->test_mode =3D 0; - return xhci_reset(xhci); + return xhci_reset(xhci, XHCI_RESET_SHORT_USEC); } =20 void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port, @@ -1088,6 +1088,9 @@ static void xhci_get_usb2_port_status(struct xhci_por= t *port, u32 *status, if (link_state =3D=3D XDEV_U2) *status |=3D USB_PORT_STAT_L1; if (link_state =3D=3D XDEV_U0) { + if (bus_state->resume_done[portnum]) + usb_hcd_end_port_resume(&port->rhub->hcd->self, + portnum); bus_state->resume_done[portnum] =3D 0; clear_bit(portnum, &bus_state->resuming_ports); if (bus_state->suspended_ports & (1 << portnum)) { diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 0e312066c5c6..b398d3fdabf6 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -2583,7 +2583,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) =20 fail: xhci_halt(xhci); - xhci_reset(xhci); + xhci_reset(xhci, XHCI_RESET_SHORT_USEC); xhci_mem_cleanup(xhci); return -ENOMEM; } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index d7c0bf494d93..2c1cc9480887 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -65,7 +65,7 @@ static bool td_on_ring(struct xhci_td *td, struct xhci_ri= ng *ring) * handshake done). There are two failure modes: "usec" have passed (maj= or * hardware flakeout), or the register reads as all-ones (hardware removed= ). */ -int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec) +int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, u64 timeout_us) { u32 result; int ret; @@ -73,7 +73,7 @@ int xhci_handshake(void __iomem *ptr, u32 mask, u32 done,= int usec) ret =3D readl_poll_timeout_atomic(ptr, result, (result & mask) =3D=3D done || result =3D=3D U32_MAX, - 1, usec); + 1, timeout_us); if (result =3D=3D U32_MAX) /* card removed */ return -ENODEV; =20 @@ -162,7 +162,7 @@ int xhci_start(struct xhci_hcd *xhci) * Transactions will be terminated immediately, and operational registers * will be set to their defaults. */ -int xhci_reset(struct xhci_hcd *xhci) +int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us) { u32 command; u32 state; @@ -195,8 +195,7 @@ int xhci_reset(struct xhci_hcd *xhci) if (xhci->quirks & XHCI_INTEL_HOST) udelay(1000); =20 - ret =3D xhci_handshake(&xhci->op_regs->command, - CMD_RESET, 0, 10 * 1000 * 1000); + ret =3D xhci_handshake(&xhci->op_regs->command, CMD_RESET, 0, timeout_us); if (ret) return ret; =20 @@ -209,8 +208,7 @@ int xhci_reset(struct xhci_hcd *xhci) * xHCI cannot write to any doorbells or operational registers other * than status until the "Controller Not Ready" flag is cleared. */ - ret =3D xhci_handshake(&xhci->op_regs->status, - STS_CNR, 0, 10 * 1000 * 1000); + ret =3D xhci_handshake(&xhci->op_regs->status, STS_CNR, 0, timeout_us); =20 xhci->usb2_rhub.bus_state.port_c_suspend =3D 0; xhci->usb2_rhub.bus_state.suspended_ports =3D 0; @@ -731,7 +729,7 @@ static void xhci_stop(struct usb_hcd *hcd) xhci->xhc_state |=3D XHCI_STATE_HALTED; xhci->cmd_ring_state =3D CMD_RING_STATE_STOPPED; xhci_halt(xhci); - xhci_reset(xhci); + xhci_reset(xhci, XHCI_RESET_SHORT_USEC); spin_unlock_irq(&xhci->lock); =20 xhci_cleanup_msix(xhci); @@ -784,7 +782,7 @@ void xhci_shutdown(struct usb_hcd *hcd) xhci_halt(xhci); /* Workaround for spurious wakeups at shutdown with HSW */ if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) - xhci_reset(xhci); + xhci_reset(xhci, XHCI_RESET_SHORT_USEC); spin_unlock_irq(&xhci->lock); =20 xhci_cleanup_msix(xhci); @@ -1170,7 +1168,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernate= d) xhci_dbg(xhci, "Stop HCD\n"); xhci_halt(xhci); xhci_zero_64b_regs(xhci); - retval =3D xhci_reset(xhci); + retval =3D xhci_reset(xhci, XHCI_RESET_LONG_USEC); spin_unlock_irq(&xhci->lock); if (retval) return retval; @@ -5318,7 +5316,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quir= ks_t get_quirks) =20 xhci_dbg(xhci, "Resetting HCD\n"); /* Reset the internal HC memory state and registers. */ - retval =3D xhci_reset(xhci); + retval =3D xhci_reset(xhci, XHCI_RESET_LONG_USEC); if (retval) return retval; xhci_dbg(xhci, "Reset complete\n"); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 5a75fe563123..bc0789229527 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -229,6 +229,9 @@ struct xhci_op_regs { #define CMD_ETE (1 << 14) /* bits 15:31 are reserved (and should be preserved on writes). */ =20 +#define XHCI_RESET_LONG_USEC (10 * 1000 * 1000) +#define XHCI_RESET_SHORT_USEC (250 * 1000) + /* IMAN - Interrupt Management Register */ #define IMAN_IE (1 << 1) #define IMAN_IP (1 << 0) @@ -2083,11 +2086,11 @@ void xhci_free_container_ctx(struct xhci_hcd *xhci, =20 /* xHCI host controller glue */ typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *); -int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec); +int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, u64 timeout_us); void xhci_quiesce(struct xhci_hcd *xhci); int xhci_halt(struct xhci_hcd *xhci); int xhci_start(struct xhci_hcd *xhci); -int xhci_reset(struct xhci_hcd *xhci); +int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us); int xhci_run(struct usb_hcd *hcd); int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks); void xhci_shutdown(struct usb_hcd *hcd); @@ -2467,6 +2470,8 @@ static inline const char *xhci_decode_ctrl_ctx(char *= str, unsigned int bit; int ret =3D 0; =20 + str[0] =3D '\0'; + if (drop) { ret =3D sprintf(str, "Drop:"); for_each_set_bit(bit, &drop, 32) @@ -2624,8 +2629,11 @@ static inline const char *xhci_decode_usbsts(char *s= tr, u32 usbsts) { int ret =3D 0; =20 + ret =3D sprintf(str, " 0x%08x", usbsts); + if (usbsts =3D=3D ~(u32)0) - return " 0xffffffff"; + return str; + if (usbsts & STS_HALT) ret +=3D sprintf(str + ret, " HCHalted"); if (usbsts & STS_FATAL) diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index de5c01257060..ef8d1c73c754 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -66,6 +66,7 @@ config USB_SERIAL_SIMPLE - Libtransistor USB console - a number of Motorola phones - Motorola Tetra devices + - Nokia mobile phones - Novatel Wireless GPS receivers - Siemens USB/MPI adapter. - ViVOtech ViVOpay USB device. diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index a70fd86f735c..88b284d61681 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -116,6 +116,7 @@ static const struct usb_device_id id_table[] =3D { { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530GC_PRODUCT_ID) }, { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) }, { USB_DEVICE(AT_VENDOR_ID, AT_VTKIT3_PRODUCT_ID) }, + { USB_DEVICE(IBM_VENDOR_ID, IBM_PRODUCT_ID) }, { } /* Terminating entry */ }; =20 @@ -435,6 +436,7 @@ static int pl2303_detect_type(struct usb_serial *serial) case 0x105: case 0x305: case 0x405: + case 0x605: /* * Assume it's an HXN-type if the device doesn't * support the old read request value. diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 6097ee8fccb2..c5406452b774 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -35,6 +35,9 @@ #define ATEN_PRODUCT_UC232B 0x2022 #define ATEN_PRODUCT_ID2 0x2118 =20 +#define IBM_VENDOR_ID 0x04b3 +#define IBM_PRODUCT_ID 0x4016 + #define IODATA_VENDOR_ID 0x04bb #define IODATA_PRODUCT_ID 0x0a03 #define IODATA_PRODUCT_ID_RSAQ5 0x0a0e diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/us= b-serial-simple.c index bd23a7cb1be2..4c6747889a19 100644 --- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -91,6 +91,11 @@ DEVICE(moto_modem, MOTO_IDS); { USB_DEVICE(0x0cad, 0x9016) } /* TPG2200 */ DEVICE(motorola_tetra, MOTOROLA_TETRA_IDS); =20 +/* Nokia mobile phone driver */ +#define NOKIA_IDS() \ + { USB_DEVICE(0x0421, 0x069a) } /* Nokia 130 (RM-1035) */ +DEVICE(nokia, NOKIA_IDS); + /* Novatel Wireless GPS driver */ #define NOVATEL_IDS() \ { USB_DEVICE(0x09d7, 0x0100) } /* NovAtel FlexPack GPS */ @@ -123,6 +128,7 @@ static struct usb_serial_driver * const serial_drivers[= ] =3D { &vivopay_device, &moto_modem_device, &motorola_tetra_device, + &nokia_device, &novatel_gps_device, &hp4x_device, &suunto_device, @@ -140,6 +146,7 @@ static const struct usb_device_id id_table[] =3D { VIVOPAY_IDS(), MOTO_IDS(), MOTOROLA_TETRA_IDS(), + NOKIA_IDS(), NOVATEL_IDS(), HP4X_IDS(), SUUNTO_IDS(), diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6= 250.c index 5f7d678502be..6012603f3630 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -237,36 +237,33 @@ static struct us_unusual_dev ene_ub6250_unusual_dev_l= ist[] =3D { #define memstick_logaddr(logadr1, logadr0) ((((u16)(logadr1)) << 8) | (log= adr0)) =20 =20 -struct SD_STATUS { - u8 Insert:1; - u8 Ready:1; - u8 MediaChange:1; - u8 IsMMC:1; - u8 HiCapacity:1; - u8 HiSpeed:1; - u8 WtP:1; - u8 Reserved:1; -}; - -struct MS_STATUS { - u8 Insert:1; - u8 Ready:1; - u8 MediaChange:1; - u8 IsMSPro:1; - u8 IsMSPHG:1; - u8 Reserved1:1; - u8 WtP:1; - u8 Reserved2:1; -}; - -struct SM_STATUS { - u8 Insert:1; - u8 Ready:1; - u8 MediaChange:1; - u8 Reserved:3; - u8 WtP:1; - u8 IsMS:1; -}; +/* SD_STATUS bits */ +#define SD_Insert BIT(0) +#define SD_Ready BIT(1) +#define SD_MediaChange BIT(2) +#define SD_IsMMC BIT(3) +#define SD_HiCapacity BIT(4) +#define SD_HiSpeed BIT(5) +#define SD_WtP BIT(6) + /* Bit 7 reserved */ + +/* MS_STATUS bits */ +#define MS_Insert BIT(0) +#define MS_Ready BIT(1) +#define MS_MediaChange BIT(2) +#define MS_IsMSPro BIT(3) +#define MS_IsMSPHG BIT(4) + /* Bit 5 reserved */ +#define MS_WtP BIT(6) + /* Bit 7 reserved */ + +/* SM_STATUS bits */ +#define SM_Insert BIT(0) +#define SM_Ready BIT(1) +#define SM_MediaChange BIT(2) + /* Bits 3-5 reserved */ +#define SM_WtP BIT(6) +#define SM_IsMS BIT(7) =20 struct ms_bootblock_cis { u8 bCistplDEVICE[6]; /* 0 */ @@ -437,9 +434,9 @@ struct ene_ub6250_info { u8 *bbuf; =20 /* for 6250 code */ - struct SD_STATUS SD_Status; - struct MS_STATUS MS_Status; - struct SM_STATUS SM_Status; + u8 SD_Status; + u8 MS_Status; + u8 SM_Status; =20 /* ----- SD Control Data ---------------- */ /*SD_REGISTER SD_Regs; */ @@ -602,7 +599,7 @@ static int sd_scsi_test_unit_ready(struct us_data *us, = struct scsi_cmnd *srb) { struct ene_ub6250_info *info =3D (struct ene_ub6250_info *) us->extra; =20 - if (info->SD_Status.Insert && info->SD_Status.Ready) + if ((info->SD_Status & SD_Insert) && (info->SD_Status & SD_Ready)) return USB_STOR_TRANSPORT_GOOD; else { ene_sd_init(us); @@ -622,7 +619,7 @@ static int sd_scsi_mode_sense(struct us_data *us, struc= t scsi_cmnd *srb) 0x0b, 0x00, 0x80, 0x08, 0x00, 0x00, 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 }; =20 - if (info->SD_Status.WtP) + if (info->SD_Status & SD_WtP) usb_stor_set_xfer_buf(mediaWP, 12, srb); else usb_stor_set_xfer_buf(mediaNoWP, 12, srb); @@ -641,9 +638,9 @@ static int sd_scsi_read_capacity(struct us_data *us, st= ruct scsi_cmnd *srb) struct ene_ub6250_info *info =3D (struct ene_ub6250_info *) us->extra; =20 usb_stor_dbg(us, "sd_scsi_read_capacity\n"); - if (info->SD_Status.HiCapacity) { + if (info->SD_Status & SD_HiCapacity) { bl_len =3D 0x200; - if (info->SD_Status.IsMMC) + if (info->SD_Status & SD_IsMMC) bl_num =3D info->HC_C_SIZE-1; else bl_num =3D (info->HC_C_SIZE + 1) * 1024 - 1; @@ -693,7 +690,7 @@ static int sd_scsi_read(struct us_data *us, struct scsi= _cmnd *srb) return USB_STOR_TRANSPORT_ERROR; } =20 - if (info->SD_Status.HiCapacity) + if (info->SD_Status & SD_HiCapacity) bnByte =3D bn; =20 /* set up the command wrapper */ @@ -733,7 +730,7 @@ static int sd_scsi_write(struct us_data *us, struct scs= i_cmnd *srb) return USB_STOR_TRANSPORT_ERROR; } =20 - if (info->SD_Status.HiCapacity) + if (info->SD_Status & SD_HiCapacity) bnByte =3D bn; =20 /* set up the command wrapper */ @@ -1456,7 +1453,7 @@ static int ms_scsi_test_unit_ready(struct us_data *us= , struct scsi_cmnd *srb) struct ene_ub6250_info *info =3D (struct ene_ub6250_info *)(us->extra); =20 /* pr_info("MS_SCSI_Test_Unit_Ready\n"); */ - if (info->MS_Status.Insert && info->MS_Status.Ready) { + if ((info->MS_Status & MS_Insert) && (info->MS_Status & MS_Ready)) { return USB_STOR_TRANSPORT_GOOD; } else { ene_ms_init(us); @@ -1476,7 +1473,7 @@ static int ms_scsi_mode_sense(struct us_data *us, str= uct scsi_cmnd *srb) 0x0b, 0x00, 0x80, 0x08, 0x00, 0x00, 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 }; =20 - if (info->MS_Status.WtP) + if (info->MS_Status & MS_WtP) usb_stor_set_xfer_buf(mediaWP, 12, srb); else usb_stor_set_xfer_buf(mediaNoWP, 12, srb); @@ -1495,7 +1492,7 @@ static int ms_scsi_read_capacity(struct us_data *us, = struct scsi_cmnd *srb) =20 usb_stor_dbg(us, "ms_scsi_read_capacity\n"); bl_len =3D 0x200; - if (info->MS_Status.IsMSPro) + if (info->MS_Status & MS_IsMSPro) bl_num =3D info->MSP_TotalBlock - 1; else bl_num =3D info->MS_Lib.NumberOfLogBlock * info->MS_Lib.blockSize * 2 - = 1; @@ -1650,7 +1647,7 @@ static int ms_scsi_read(struct us_data *us, struct sc= si_cmnd *srb) if (bn > info->bl_num) return USB_STOR_TRANSPORT_ERROR; =20 - if (info->MS_Status.IsMSPro) { + if (info->MS_Status & MS_IsMSPro) { result =3D ene_load_bincode(us, MSP_RW_PATTERN); if (result !=3D USB_STOR_XFER_GOOD) { usb_stor_dbg(us, "Load MPS RW pattern Fail !!\n"); @@ -1751,7 +1748,7 @@ static int ms_scsi_write(struct us_data *us, struct s= csi_cmnd *srb) if (bn > info->bl_num) return USB_STOR_TRANSPORT_ERROR; =20 - if (info->MS_Status.IsMSPro) { + if (info->MS_Status & MS_IsMSPro) { result =3D ene_load_bincode(us, MSP_RW_PATTERN); if (result !=3D USB_STOR_XFER_GOOD) { pr_info("Load MSP RW pattern Fail !!\n"); @@ -1859,12 +1856,12 @@ static int ene_get_card_status(struct us_data *us, = u8 *buf) =20 tmpreg =3D (u16) reg4b; reg4b =3D *(u32 *)(&buf[0x14]); - if (info->SD_Status.HiCapacity && !info->SD_Status.IsMMC) + if ((info->SD_Status & SD_HiCapacity) && !(info->SD_Status & SD_IsMMC)) info->HC_C_SIZE =3D (reg4b >> 8) & 0x3fffff; =20 info->SD_C_SIZE =3D ((tmpreg & 0x03) << 10) | (u16)(reg4b >> 22); info->SD_C_SIZE_MULT =3D (u8)(reg4b >> 7) & 0x07; - if (info->SD_Status.HiCapacity && info->SD_Status.IsMMC) + if ((info->SD_Status & SD_HiCapacity) && (info->SD_Status & SD_IsMMC)) info->HC_C_SIZE =3D *(u32 *)(&buf[0x100]); =20 if (info->SD_READ_BL_LEN > SD_BLOCK_LEN) { @@ -2076,6 +2073,7 @@ static int ene_ms_init(struct us_data *us) u16 MSP_BlockSize, MSP_UserAreaBlocks; struct ene_ub6250_info *info =3D (struct ene_ub6250_info *) us->extra; u8 *bbuf =3D info->bbuf; + unsigned int s; =20 printk(KERN_INFO "transport --- ENE_MSInit\n"); =20 @@ -2100,15 +2098,16 @@ static int ene_ms_init(struct us_data *us) return USB_STOR_TRANSPORT_ERROR; } /* the same part to test ENE */ - info->MS_Status =3D *(struct MS_STATUS *) bbuf; - - if (info->MS_Status.Insert && info->MS_Status.Ready) { - printk(KERN_INFO "Insert =3D %x\n", info->MS_Status.Insert); - printk(KERN_INFO "Ready =3D %x\n", info->MS_Status.Ready); - printk(KERN_INFO "IsMSPro =3D %x\n", info->MS_Status.IsMSPro); - printk(KERN_INFO "IsMSPHG =3D %x\n", info->MS_Status.IsMSPHG); - printk(KERN_INFO "WtP=3D %x\n", info->MS_Status.WtP); - if (info->MS_Status.IsMSPro) { + info->MS_Status =3D bbuf[0]; + + s =3D info->MS_Status; + if ((s & MS_Insert) && (s & MS_Ready)) { + printk(KERN_INFO "Insert =3D %x\n", !!(s & MS_Insert)); + printk(KERN_INFO "Ready =3D %x\n", !!(s & MS_Ready)); + printk(KERN_INFO "IsMSPro =3D %x\n", !!(s & MS_IsMSPro)); + printk(KERN_INFO "IsMSPHG =3D %x\n", !!(s & MS_IsMSPHG)); + printk(KERN_INFO "WtP=3D %x\n", !!(s & MS_WtP)); + if (s & MS_IsMSPro) { MSP_BlockSize =3D (bbuf[6] << 8) | bbuf[7]; MSP_UserAreaBlocks =3D (bbuf[10] << 8) | bbuf[11]; info->MSP_TotalBlock =3D MSP_BlockSize * MSP_UserAreaBlocks; @@ -2169,17 +2168,17 @@ static int ene_sd_init(struct us_data *us) return USB_STOR_TRANSPORT_ERROR; } =20 - info->SD_Status =3D *(struct SD_STATUS *) bbuf; - if (info->SD_Status.Insert && info->SD_Status.Ready) { - struct SD_STATUS *s =3D &info->SD_Status; + info->SD_Status =3D bbuf[0]; + if ((info->SD_Status & SD_Insert) && (info->SD_Status & SD_Ready)) { + unsigned int s =3D info->SD_Status; =20 ene_get_card_status(us, bbuf); - usb_stor_dbg(us, "Insert =3D %x\n", s->Insert); - usb_stor_dbg(us, "Ready =3D %x\n", s->Ready); - usb_stor_dbg(us, "IsMMC =3D %x\n", s->IsMMC); - usb_stor_dbg(us, "HiCapacity =3D %x\n", s->HiCapacity); - usb_stor_dbg(us, "HiSpeed =3D %x\n", s->HiSpeed); - usb_stor_dbg(us, "WtP =3D %x\n", s->WtP); + usb_stor_dbg(us, "Insert =3D %x\n", !!(s & SD_Insert)); + usb_stor_dbg(us, "Ready =3D %x\n", !!(s & SD_Ready)); + usb_stor_dbg(us, "IsMMC =3D %x\n", !!(s & SD_IsMMC)); + usb_stor_dbg(us, "HiCapacity =3D %x\n", !!(s & SD_HiCapacity)); + usb_stor_dbg(us, "HiSpeed =3D %x\n", !!(s & SD_HiSpeed)); + usb_stor_dbg(us, "WtP =3D %x\n", !!(s & SD_WtP)); } else { usb_stor_dbg(us, "SD Card Not Ready --- %x\n", bbuf[0]); return USB_STOR_TRANSPORT_ERROR; @@ -2201,14 +2200,14 @@ static int ene_init(struct us_data *us) =20 misc_reg03 =3D bbuf[0]; if (misc_reg03 & 0x01) { - if (!info->SD_Status.Ready) { + if (!(info->SD_Status & SD_Ready)) { result =3D ene_sd_init(us); if (result !=3D USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; } } if (misc_reg03 & 0x02) { - if (!info->MS_Status.Ready) { + if (!(info->MS_Status & MS_Ready)) { result =3D ene_ms_init(us); if (result !=3D USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -2307,14 +2306,14 @@ static int ene_transport(struct scsi_cmnd *srb, str= uct us_data *us) =20 /*US_DEBUG(usb_stor_show_command(us, srb)); */ scsi_set_resid(srb, 0); - if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready))) + if (unlikely(!(info->SD_Status & SD_Ready) || (info->MS_Status & MS_Ready= ))) result =3D ene_init(us); if (result =3D=3D USB_STOR_XFER_GOOD) { result =3D USB_STOR_TRANSPORT_ERROR; - if (info->SD_Status.Ready) + if (info->SD_Status & SD_Ready) result =3D sd_scsi_irp(us, srb); =20 - if (info->MS_Status.Ready) + if (info->MS_Status & MS_Ready) result =3D ms_scsi_irp(us, srb); } return result; @@ -2378,7 +2377,6 @@ static int ene_ub6250_probe(struct usb_interface *int= f, =20 static int ene_ub6250_resume(struct usb_interface *iface) { - u8 tmp =3D 0; struct us_data *us =3D usb_get_intfdata(iface); struct ene_ub6250_info *info =3D (struct ene_ub6250_info *)(us->extra); =20 @@ -2390,17 +2388,16 @@ static int ene_ub6250_resume(struct usb_interface *= iface) mutex_unlock(&us->dev_mutex); =20 info->Power_IsResum =3D true; - /*info->SD_Status.Ready =3D 0; */ - info->SD_Status =3D *(struct SD_STATUS *)&tmp; - info->MS_Status =3D *(struct MS_STATUS *)&tmp; - info->SM_Status =3D *(struct SM_STATUS *)&tmp; + /* info->SD_Status &=3D ~SD_Ready; */ + info->SD_Status =3D 0; + info->MS_Status =3D 0; + info->SM_Status =3D 0; =20 return 0; } =20 static int ene_ub6250_reset_resume(struct usb_interface *iface) { - u8 tmp =3D 0; struct us_data *us =3D usb_get_intfdata(iface); struct ene_ub6250_info *info =3D (struct ene_ub6250_info *)(us->extra); =20 @@ -2412,10 +2409,10 @@ static int ene_ub6250_reset_resume(struct usb_inter= face *iface) * the device */ info->Power_IsResum =3D true; - /*info->SD_Status.Ready =3D 0; */ - info->SD_Status =3D *(struct SD_STATUS *)&tmp; - info->MS_Status =3D *(struct MS_STATUS *)&tmp; - info->SM_Status =3D *(struct SM_STATUS *)&tmp; + /* info->SD_Status &=3D ~SD_Ready; */ + info->SD_Status =3D 0; + info->MS_Status =3D 0; + info->SM_Status =3D 0; =20 return 0; } diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek= _cr.c index 3789698d9d3c..0c423916d7bf 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -365,7 +365,7 @@ static int rts51x_read_mem(struct us_data *us, u16 addr= , u8 *data, u16 len) =20 buf =3D kmalloc(len, GFP_NOIO); if (buf =3D=3D NULL) - return USB_STOR_TRANSPORT_ERROR; + return -ENOMEM; =20 usb_stor_dbg(us, "addr =3D 0x%x, len =3D %d\n", addr, len); =20 diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index 7ffcda94d323..16b4560216ba 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -256,6 +256,10 @@ static int tps6598x_connect(struct tps6598x *tps, u32 = status) typec_set_pwr_opmode(tps->port, mode); typec_set_pwr_role(tps->port, TPS_STATUS_TO_TYPEC_PORTROLE(status)); typec_set_vconn_role(tps->port, TPS_STATUS_TO_TYPEC_VCONN(status)); + if (TPS_STATUS_TO_UPSIDE_DOWN(status)) + typec_set_orientation(tps->port, TYPEC_ORIENTATION_REVERSE); + else + typec_set_orientation(tps->port, TYPEC_ORIENTATION_NORMAL); tps6598x_set_data_role(tps, TPS_STATUS_TO_TYPEC_DATAROLE(status), true); =20 tps->partner =3D typec_register_partner(tps->port, &desc); @@ -278,6 +282,7 @@ static void tps6598x_disconnect(struct tps6598x *tps, u= 32 status) typec_set_pwr_opmode(tps->port, TYPEC_PWR_MODE_USB); typec_set_pwr_role(tps->port, TPS_STATUS_TO_TYPEC_PORTROLE(status)); typec_set_vconn_role(tps->port, TPS_STATUS_TO_TYPEC_VCONN(status)); + typec_set_orientation(tps->port, TYPEC_ORIENTATION_NONE); tps6598x_set_data_role(tps, TPS_STATUS_TO_TYPEC_DATAROLE(status), false); =20 power_supply_changed(tps->psy); diff --git a/drivers/usb/typec/tipd/tps6598x.h b/drivers/usb/typec/tipd/tps= 6598x.h index 3dae84c524fb..527857549d69 100644 --- a/drivers/usb/typec/tipd/tps6598x.h +++ b/drivers/usb/typec/tipd/tps6598x.h @@ -17,6 +17,7 @@ /* TPS_REG_STATUS bits */ #define TPS_STATUS_PLUG_PRESENT BIT(0) #define TPS_STATUS_PLUG_UPSIDE_DOWN BIT(4) +#define TPS_STATUS_TO_UPSIDE_DOWN(s) (!!((s) & TPS_STATUS_PLUG_UPSIDE_DOWN= )) #define TPS_STATUS_PORTROLE BIT(5) #define TPS_STATUS_TO_TYPEC_PORTROLE(s) (!!((s) & TPS_STATUS_PORTROLE)) #define TPS_STATUS_DATAROLE BIT(6) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5= _vnet.c index 7b4ab7cfc359..57bed3d74060 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -1680,7 +1680,7 @@ static void mlx5_vdpa_kick_vq(struct vdpa_device *vde= v, u16 idx) return; =20 if (unlikely(is_ctrl_vq_idx(mvdev, idx))) { - if (!mvdev->cvq.ready) + if (!mvdev->wq || !mvdev->cvq.ready) return; =20 wqent =3D kzalloc(sizeof(*wqent), GFP_ATOMIC); @@ -1916,11 +1916,25 @@ static u64 mlx5_vdpa_get_features(struct vdpa_devic= e *vdev) return ndev->mvdev.mlx_features; } =20 -static int verify_min_features(struct mlx5_vdpa_dev *mvdev, u64 features) +static int verify_driver_features(struct mlx5_vdpa_dev *mvdev, u64 feature= s) { + /* Minimum features to expect */ if (!(features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM))) return -EOPNOTSUPP; =20 + /* Double check features combination sent down by the driver. + * Fail invalid features due to absence of the depended feature. + * + * Per VIRTIO v1.1 specification, section 5.1.3.1 Feature bit + * requirements: "VIRTIO_NET_F_MQ Requires VIRTIO_NET_F_CTRL_VQ". + * By failing the invalid features sent down by untrusted drivers, + * we're assured the assumption made upon is_index_valid() and + * is_ctrl_vq_idx() will not be compromised. + */ + if ((features & (BIT_ULL(VIRTIO_NET_F_MQ) | BIT_ULL(VIRTIO_NET_F_CTRL_VQ)= )) =3D=3D + BIT_ULL(VIRTIO_NET_F_MQ)) + return -EINVAL; + return 0; } =20 @@ -1996,7 +2010,7 @@ static int mlx5_vdpa_set_features(struct vdpa_device = *vdev, u64 features) =20 print_features(mvdev, features, true); =20 - err =3D verify_min_features(mvdev, features); + err =3D verify_driver_features(mvdev, features); if (err) return err; =20 @@ -2659,9 +2673,12 @@ static void mlx5_vdpa_dev_del(struct vdpa_mgmt_dev *= v_mdev, struct vdpa_device * struct mlx5_vdpa_mgmtdev *mgtdev =3D container_of(v_mdev, struct mlx5_vdp= a_mgmtdev, mgtdev); struct mlx5_vdpa_dev *mvdev =3D to_mvdev(dev); struct mlx5_vdpa_net *ndev =3D to_mlx5_vdpa_ndev(mvdev); + struct workqueue_struct *wq; =20 mlx5_notifier_unregister(mvdev->mdev, &ndev->nb); - destroy_workqueue(mvdev->wq); + wq =3D mvdev->wq; + mvdev->wq =3D NULL; + destroy_workqueue(wq); _vdpa_unregister_device(dev); mgtdev->ndev =3D NULL; } diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_c= ore.c index f948e6cd2993..2e6409cc11ad 100644 --- a/drivers/vfio/pci/vfio_pci_core.c +++ b/drivers/vfio/pci/vfio_pci_core.c @@ -228,6 +228,19 @@ int vfio_pci_set_power_state(struct vfio_pci_core_devi= ce *vdev, pci_power_t stat if (!ret) { /* D3 might be unsupported via quirk, skip unless in D3 */ if (needs_save && pdev->current_state >=3D PCI_D3hot) { + /* + * The current PCI state will be saved locally in + * 'pm_save' during the D3hot transition. When the + * device state is changed to D0 again with the current + * function, then pci_store_saved_state() will restore + * the state and will free the memory pointed by + * 'pm_save'. There are few cases where the PCI power + * state can be changed to D0 without the involvement + * of the driver. For these cases, free the earlier + * allocated memory first before overwriting 'pm_save' + * to prevent the memory leak. + */ + kfree(vdev->pm_save); vdev->pm_save =3D pci_store_saved_state(pdev); } else if (needs_restore) { pci_load_and_free_saved_state(pdev, &vdev->pm_save); @@ -322,6 +335,17 @@ void vfio_pci_core_disable(struct vfio_pci_core_device= *vdev) /* For needs_reset */ lockdep_assert_held(&vdev->vdev.dev_set->lock); =20 + /* + * This function can be invoked while the power state is non-D0. + * This function calls __pci_reset_function_locked() which internally + * can use pci_pm_reset() for the function reset. pci_pm_reset() will + * fail if the power state is non-D0. Also, for the devices which + * have NoSoftRst-, the reset function can cause the PCI config space + * reset without restoring the original state (saved locally in + * 'vdev->pm_save'). + */ + vfio_pci_set_power_state(vdev, PCI_D0); + /* Stop the device from further DMA */ pci_clear_master(pdev); =20 @@ -921,6 +945,19 @@ long vfio_pci_core_ioctl(struct vfio_device *core_vdev= , unsigned int cmd, return -EINVAL; =20 vfio_pci_zap_and_down_write_memory_lock(vdev); + + /* + * This function can be invoked while the power state is non-D0. + * If pci_try_reset_function() has been called while the power + * state is non-D0, then pci_try_reset_function() will + * internally set the power state to D0 without vfio driver + * involvement. For the devices which have NoSoftRst-, the + * reset function can cause the PCI config space reset without + * restoring the original state (saved locally in + * 'vdev->pm_save'). + */ + vfio_pci_set_power_state(vdev, PCI_D0); + ret =3D pci_try_reset_function(vdev->pdev); up_write(&vdev->memory_lock); =20 @@ -2055,6 +2092,18 @@ static int vfio_pci_dev_set_hot_reset(struct vfio_de= vice_set *dev_set, } cur_mem =3D NULL; =20 + /* + * The pci_reset_bus() will reset all the devices in the bus. + * The power state can be non-D0 for some of the devices in the bus. + * For these devices, the pci_reset_bus() will internally set + * the power state to D0 without vfio driver involvement. + * For the devices which have NoSoftRst-, the reset function can + * cause the PCI config space reset without restoring the original + * state (saved locally in 'vdev->pm_save'). + */ + list_for_each_entry(cur, &dev_set->device_list, vdev.dev_set_list) + vfio_pci_set_power_state(cur, PCI_D0); + ret =3D pci_reset_bus(pdev); =20 err_undo: @@ -2108,6 +2157,18 @@ static bool vfio_pci_dev_set_try_reset(struct vfio_d= evice_set *dev_set) if (!pdev) return false; =20 + /* + * The pci_reset_bus() will reset all the devices in the bus. + * The power state can be non-D0 for some of the devices in the bus. + * For these devices, the pci_reset_bus() will internally set + * the power state to D0 without vfio driver involvement. + * For the devices which have NoSoftRst-, the reset function can + * cause the PCI config space reset without restoring the original + * state (saved locally in 'vdev->pm_save'). + */ + list_for_each_entry(cur, &dev_set->device_list, vdev.dev_set_list) + vfio_pci_set_power_state(cur, PCI_D0); + ret =3D pci_reset_bus(pdev); if (ret) return false; diff --git a/drivers/vhost/iotlb.c b/drivers/vhost/iotlb.c index 40b098320b2a..5829cf2d0552 100644 --- a/drivers/vhost/iotlb.c +++ b/drivers/vhost/iotlb.c @@ -62,8 +62,12 @@ int vhost_iotlb_add_range_ctx(struct vhost_iotlb *iotlb, */ if (start =3D=3D 0 && last =3D=3D ULONG_MAX) { u64 mid =3D last / 2; + int err =3D vhost_iotlb_add_range_ctx(iotlb, start, mid, addr, + perm, opaque); + + if (err) + return err; =20 - vhost_iotlb_add_range_ctx(iotlb, start, mid, addr, perm, opaque); addr +=3D mid + 1; start =3D mid + 1; } diff --git a/drivers/video/fbdev/atafb.c b/drivers/video/fbdev/atafb.c index e3812a8ff55a..29e650ecfceb 100644 --- a/drivers/video/fbdev/atafb.c +++ b/drivers/video/fbdev/atafb.c @@ -1683,9 +1683,9 @@ static int falcon_setcolreg(unsigned int regno, unsig= ned int red, ((blue & 0xfc00) >> 8)); if (regno < 16) { shifter_tt.color_reg[regno] =3D - (((red & 0xe000) >> 13) | ((red & 0x1000) >> 12) << 8) | - (((green & 0xe000) >> 13) | ((green & 0x1000) >> 12) << 4) | - ((blue & 0xe000) >> 13) | ((blue & 0x1000) >> 12); + ((((red & 0xe000) >> 13) | ((red & 0x1000) >> 12)) << 8) | + ((((green & 0xe000) >> 13) | ((green & 0x1000) >> 12)) << 4) | + ((blue & 0xe000) >> 13) | ((blue & 0x1000) >> 12); ((u32 *)info->pseudo_palette)[regno] =3D ((red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11)); @@ -1971,9 +1971,9 @@ static int stste_setcolreg(unsigned int regno, unsign= ed int red, green >>=3D 12; if (ATARIHW_PRESENT(EXTD_SHIFTER)) shifter_tt.color_reg[regno] =3D - (((red & 0xe) >> 1) | ((red & 1) << 3) << 8) | - (((green & 0xe) >> 1) | ((green & 1) << 3) << 4) | - ((blue & 0xe) >> 1) | ((blue & 1) << 3); + ((((red & 0xe) >> 1) | ((red & 1) << 3)) << 8) | + ((((green & 0xe) >> 1) | ((green & 1) << 3)) << 4) | + ((blue & 0xe) >> 1) | ((blue & 1) << 3); else shifter_tt.color_reg[regno] =3D ((red & 0xe) << 7) | diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_= lcdfb.c index 355b6120dc4f..1fc8de4ecbeb 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -1062,15 +1062,16 @@ static int __init atmel_lcdfb_probe(struct platform= _device *pdev) =20 INIT_LIST_HEAD(&info->modelist); =20 - if (pdev->dev.of_node) { - ret =3D atmel_lcdfb_of_init(sinfo); - if (ret) - goto free_info; - } else { + if (!pdev->dev.of_node) { dev_err(dev, "cannot get default configuration\n"); goto free_info; } =20 + ret =3D atmel_lcdfb_of_init(sinfo); + if (ret) + goto free_info; + + ret =3D -ENODEV; if (!sinfo->config) goto free_info; =20 diff --git a/drivers/video/fbdev/cirrusfb.c b/drivers/video/fbdev/cirrusfb.c index 93802abbbc72..3d47c347b897 100644 --- a/drivers/video/fbdev/cirrusfb.c +++ b/drivers/video/fbdev/cirrusfb.c @@ -469,7 +469,7 @@ static int cirrusfb_check_mclk(struct fb_info *info, lo= ng freq) return 0; } =20 -static int cirrusfb_check_pixclock(const struct fb_var_screeninfo *var, +static int cirrusfb_check_pixclock(struct fb_var_screeninfo *var, struct fb_info *info) { long freq; @@ -478,9 +478,7 @@ static int cirrusfb_check_pixclock(const struct fb_var_= screeninfo *var, unsigned maxclockidx =3D var->bits_per_pixel >> 3; =20 /* convert from ps to kHz */ - freq =3D PICOS2KHZ(var->pixclock); - - dev_dbg(info->device, "desired pixclock: %ld kHz\n", freq); + freq =3D PICOS2KHZ(var->pixclock ? : 1); =20 maxclock =3D cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx]; cinfo->multiplexing =3D 0; @@ -488,11 +486,13 @@ static int cirrusfb_check_pixclock(const struct fb_va= r_screeninfo *var, /* If the frequency is greater than we can support, we might be able * to use multiplexing for the video mode */ if (freq > maxclock) { - dev_err(info->device, - "Frequency greater than maxclock (%ld kHz)\n", - maxclock); - return -EINVAL; + var->pixclock =3D KHZ2PICOS(maxclock); + + while ((freq =3D PICOS2KHZ(var->pixclock)) > maxclock) + var->pixclock++; } + dev_dbg(info->device, "desired pixclock: %ld kHz\n", freq); + /* * Additional constraint: 8bpp uses DAC clock doubling to allow maximum * pixel clock diff --git a/drivers/video/fbdev/controlfb.c b/drivers/video/fbdev/controlf= b.c index 509311471d51..bd59e7b11ed5 100644 --- a/drivers/video/fbdev/controlfb.c +++ b/drivers/video/fbdev/controlfb.c @@ -67,7 +67,9 @@ #define out_8(addr, val) (void)(val) #define in_le32(addr) 0 #define out_le32(addr, val) (void)(val) +#ifndef pgprot_cached_wthru #define pgprot_cached_wthru(prot) (prot) +#endif #else static void invalid_vram_cache(void __force *addr) { diff --git a/drivers/video/fbdev/core/fbcvt.c b/drivers/video/fbdev/core/fb= cvt.c index 55d2bd0ce5c0..64843464c661 100644 --- a/drivers/video/fbdev/core/fbcvt.c +++ b/drivers/video/fbdev/core/fbcvt.c @@ -214,9 +214,11 @@ static u32 fb_cvt_aspect_ratio(struct fb_cvt_data *cvt) static void fb_cvt_print_name(struct fb_cvt_data *cvt) { u32 pixcount, pixcount_mod; - int cnt =3D 255, offset =3D 0, read =3D 0; - u8 *buf =3D kzalloc(256, GFP_KERNEL); + int size =3D 256; + int off =3D 0; + u8 *buf; =20 + buf =3D kzalloc(size, GFP_KERNEL); if (!buf) return; =20 @@ -224,43 +226,30 @@ static void fb_cvt_print_name(struct fb_cvt_data *cvt) pixcount_mod =3D (cvt->xres * (cvt->yres/cvt->interlace)) % 1000000; pixcount_mod /=3D 1000; =20 - read =3D snprintf(buf+offset, cnt, "fbcvt: %dx%d@%d: CVT Name - ", - cvt->xres, cvt->yres, cvt->refresh); - offset +=3D read; - cnt -=3D read; + off +=3D scnprintf(buf + off, size - off, "fbcvt: %dx%d@%d: CVT Name - ", + cvt->xres, cvt->yres, cvt->refresh); =20 - if (cvt->status) - snprintf(buf+offset, cnt, "Not a CVT standard - %d.%03d Mega " - "Pixel Image\n", pixcount, pixcount_mod); - else { - if (pixcount) { - read =3D snprintf(buf+offset, cnt, "%d", pixcount); - cnt -=3D read; - offset +=3D read; - } + if (cvt->status) { + off +=3D scnprintf(buf + off, size - off, + "Not a CVT standard - %d.%03d Mega Pixel Image\n", + pixcount, pixcount_mod); + } else { + if (pixcount) + off +=3D scnprintf(buf + off, size - off, "%d", pixcount); =20 - read =3D snprintf(buf+offset, cnt, ".%03dM", pixcount_mod); - cnt -=3D read; - offset +=3D read; + off +=3D scnprintf(buf + off, size - off, ".%03dM", pixcount_mod); =20 if (cvt->aspect_ratio =3D=3D 0) - read =3D snprintf(buf+offset, cnt, "3"); + off +=3D scnprintf(buf + off, size - off, "3"); else if (cvt->aspect_ratio =3D=3D 3) - read =3D snprintf(buf+offset, cnt, "4"); + off +=3D scnprintf(buf + off, size - off, "4"); else if (cvt->aspect_ratio =3D=3D 1 || cvt->aspect_ratio =3D=3D 4) - read =3D snprintf(buf+offset, cnt, "9"); + off +=3D scnprintf(buf + off, size - off, "9"); else if (cvt->aspect_ratio =3D=3D 2) - read =3D snprintf(buf+offset, cnt, "A"); - else - read =3D 0; - cnt -=3D read; - offset +=3D read; - - if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) { - read =3D snprintf(buf+offset, cnt, "-R"); - cnt -=3D read; - offset +=3D read; - } + off +=3D scnprintf(buf + off, size - off, "A"); + + if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) + off +=3D scnprintf(buf + off, size - off, "-R"); } =20 printk(KERN_INFO "%s\n", buf); diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fb= mem.c index 0fa7ede94fa6..b585339509b0 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -1557,18 +1558,36 @@ static void do_remove_conflicting_framebuffers(stru= ct apertures_struct *a, /* check all firmware fbs and kick off if the base addr overlaps */ for_each_registered_fb(i) { struct apertures_struct *gen_aper; + struct device *device; =20 if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE)) continue; =20 gen_aper =3D registered_fb[i]->apertures; + device =3D registered_fb[i]->device; if (fb_do_apertures_overlap(gen_aper, a) || (primary && gen_aper && gen_aper->count && gen_aper->ranges[0].base =3D=3D VGA_FB_PHYS)) { =20 printk(KERN_INFO "fb%d: switching to %s from %s\n", i, name, registered_fb[i]->fix.id); - do_unregister_framebuffer(registered_fb[i]); + + /* + * If we kick-out a firmware driver, we also want to remove + * the underlying platform device, such as simple-framebuffer, + * VESA, EFI, etc. A native driver will then be able to + * allocate the memory range. + * + * If it's not a platform device, at least print a warning. A + * fix would add code to remove the device from the system. + */ + if (dev_is_platform(device)) { + registered_fb[i]->forced_out =3D true; + platform_device_unregister(to_platform_device(device)); + } else { + pr_warn("fb%d: cannot remove device\n", i); + do_unregister_framebuffer(registered_fb[i]); + } } } } @@ -1898,9 +1917,13 @@ EXPORT_SYMBOL(register_framebuffer); void unregister_framebuffer(struct fb_info *fb_info) { - mutex_lock(®istration_lock); + bool forced_out =3D fb_info->forced_out; + + if (!forced_out) + mutex_lock(®istration_lock); do_unregister_framebuffer(fb_info); - mutex_unlock(®istration_lock); + if (!forced_out) + mutex_unlock(®istration_lock); } EXPORT_SYMBOL(unregister_framebuffer); =20 diff --git a/drivers/video/fbdev/matrox/matroxfb_base.c b/drivers/video/fbd= ev/matrox/matroxfb_base.c index 5c82611e93d9..236521b19daf 100644 --- a/drivers/video/fbdev/matrox/matroxfb_base.c +++ b/drivers/video/fbdev/matrox/matroxfb_base.c @@ -1377,7 +1377,7 @@ static struct video_board vbG200 =3D { .lowlevel =3D &matrox_G100 }; static struct video_board vbG200eW =3D { - .maxvram =3D 0x800000, + .maxvram =3D 0x100000, .maxdisplayable =3D 0x800000, .accelID =3D FB_ACCEL_MATROX_MGAG200, .lowlevel =3D &matrox_G100 diff --git a/drivers/video/fbdev/nvidia/nv_i2c.c b/drivers/video/fbdev/nvid= ia/nv_i2c.c index d7994a173245..0b48965a6420 100644 --- a/drivers/video/fbdev/nvidia/nv_i2c.c +++ b/drivers/video/fbdev/nvidia/nv_i2c.c @@ -86,7 +86,7 @@ static int nvidia_setup_i2c_bus(struct nvidia_i2c_chan *c= han, const char *name, { int rc; =20 - strcpy(chan->adapter.name, name); + strscpy(chan->adapter.name, name, sizeof(chan->adapter.name)); chan->adapter.owner =3D THIS_MODULE; chan->adapter.class =3D i2c_class; chan->adapter.algo_data =3D &chan->algo; diff --git a/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c b/dr= ivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c index 2fa436475b40..c8ad3ef42bd3 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c @@ -246,6 +246,7 @@ static int dvic_probe_of(struct platform_device *pdev) adapter_node =3D of_parse_phandle(node, "ddc-i2c-bus", 0); if (adapter_node) { adapter =3D of_get_i2c_adapter_by_node(adapter_node); + of_node_put(adapter_node); if (adapter =3D=3D NULL) { dev_err(&pdev->dev, "failed to parse ddc-i2c-bus\n"); omap_dss_put_device(ddata->in); diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c b/dri= vers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c index 4b0793abdd84..a2c7c5cb1523 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c @@ -409,7 +409,7 @@ static ssize_t dsicm_num_errors_show(struct device *dev, if (r) return r; =20 - return snprintf(buf, PAGE_SIZE, "%d\n", errors); + return sysfs_emit(buf, "%d\n", errors); } =20 static ssize_t dsicm_hw_revision_show(struct device *dev, @@ -439,7 +439,7 @@ static ssize_t dsicm_hw_revision_show(struct device *de= v, if (r) return r; =20 - return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x\n", id1, id2, id3); + return sysfs_emit(buf, "%02x.%02x.%02x\n", id1, id2, id3); } =20 static ssize_t dsicm_store_ulps(struct device *dev, @@ -487,7 +487,7 @@ static ssize_t dsicm_show_ulps(struct device *dev, t =3D ddata->ulps_enabled; mutex_unlock(&ddata->lock); =20 - return snprintf(buf, PAGE_SIZE, "%u\n", t); + return sysfs_emit(buf, "%u\n", t); } =20 static ssize_t dsicm_store_ulps_timeout(struct device *dev, @@ -532,7 +532,7 @@ static ssize_t dsicm_show_ulps_timeout(struct device *d= ev, t =3D ddata->ulps_timeout; mutex_unlock(&ddata->lock); =20 - return snprintf(buf, PAGE_SIZE, "%u\n", t); + return sysfs_emit(buf, "%u\n", t); } =20 static DEVICE_ATTR(num_dsi_errors, S_IRUGO, dsicm_num_errors_show, NULL); diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm= .c b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c index 8d8b5ff7d43c..3696eb09b69b 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c @@ -476,7 +476,7 @@ static ssize_t show_cabc_available_modes(struct device = *dev, int i; =20 if (!ddata->has_cabc) - return snprintf(buf, PAGE_SIZE, "%s\n", cabc_modes[0]); + return sysfs_emit(buf, "%s\n", cabc_modes[0]); =20 for (i =3D 0, len =3D 0; len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++) diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1= .c b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c index afac1d9445aa..57b7d1f49096 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c @@ -169,7 +169,7 @@ static ssize_t tpo_td043_vmirror_show(struct device *de= v, { struct panel_drv_data *ddata =3D dev_get_drvdata(dev); =20 - return snprintf(buf, PAGE_SIZE, "%d\n", ddata->vmirror); + return sysfs_emit(buf, "%d\n", ddata->vmirror); } =20 static ssize_t tpo_td043_vmirror_store(struct device *dev, @@ -199,7 +199,7 @@ static ssize_t tpo_td043_mode_show(struct device *dev, { struct panel_drv_data *ddata =3D dev_get_drvdata(dev); =20 - return snprintf(buf, PAGE_SIZE, "%d\n", ddata->mode); + return sysfs_emit(buf, "%d\n", ddata->mode); } =20 static ssize_t tpo_td043_mode_store(struct device *dev, diff --git a/drivers/video/fbdev/sm712fb.c b/drivers/video/fbdev/sm712fb.c index 0dbc6bf8268a..092a1caa1208 100644 --- a/drivers/video/fbdev/sm712fb.c +++ b/drivers/video/fbdev/sm712fb.c @@ -1047,7 +1047,7 @@ static ssize_t smtcfb_read(struct fb_info *info, char= __user *buf, if (count + p > total_size) count =3D total_size - p; =20 - buffer =3D kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); + buffer =3D kmalloc(PAGE_SIZE, GFP_KERNEL); if (!buffer) return -ENOMEM; =20 @@ -1059,25 +1059,14 @@ static ssize_t smtcfb_read(struct fb_info *info, ch= ar __user *buf, while (count) { c =3D (count > PAGE_SIZE) ? PAGE_SIZE : count; dst =3D buffer; - for (i =3D c >> 2; i--;) { - *dst =3D fb_readl(src++); - *dst =3D big_swap(*dst); + for (i =3D (c + 3) >> 2; i--;) { + u32 val; + + val =3D fb_readl(src); + *dst =3D big_swap(val); + src++; dst++; } - if (c & 3) { - u8 *dst8 =3D (u8 *)dst; - u8 __iomem *src8 =3D (u8 __iomem *)src; - - for (i =3D c & 3; i--;) { - if (i & 1) { - *dst8++ =3D fb_readb(++src8); - } else { - *dst8++ =3D fb_readb(--src8); - src8 +=3D 2; - } - } - src =3D (u32 __iomem *)src8; - } =20 if (copy_to_user(buf, buffer, c)) { err =3D -EFAULT; @@ -1130,7 +1119,7 @@ static ssize_t smtcfb_write(struct fb_info *info, con= st char __user *buf, count =3D total_size - p; } =20 - buffer =3D kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); + buffer =3D kmalloc(PAGE_SIZE, GFP_KERNEL); if (!buffer) return -ENOMEM; =20 @@ -1148,24 +1137,11 @@ static ssize_t smtcfb_write(struct fb_info *info, c= onst char __user *buf, break; } =20 - for (i =3D c >> 2; i--;) { - fb_writel(big_swap(*src), dst++); + for (i =3D (c + 3) >> 2; i--;) { + fb_writel(big_swap(*src), dst); + dst++; src++; } - if (c & 3) { - u8 *src8 =3D (u8 *)src; - u8 __iomem *dst8 =3D (u8 __iomem *)dst; - - for (i =3D c & 3; i--;) { - if (i & 1) { - fb_writeb(*src8++, ++dst8); - } else { - fb_writeb(*src8++, --dst8); - dst8 +=3D 2; - } - } - dst =3D (u32 __iomem *)dst8; - } =20 *ppos +=3D c; buf +=3D c; diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c index bfac3ee4a642..28768c272b73 100644 --- a/drivers/video/fbdev/smscufx.c +++ b/drivers/video/fbdev/smscufx.c @@ -1656,6 +1656,7 @@ static int ufx_usb_probe(struct usb_interface *interf= ace, info->par =3D dev; info->pseudo_palette =3D dev->pseudo_palette; info->fbops =3D &ufx_ops; + INIT_LIST_HEAD(&info->modelist); =20 retval =3D fb_alloc_cmap(&info->cmap, 256, 0); if (retval < 0) { @@ -1666,8 +1667,6 @@ static int ufx_usb_probe(struct usb_interface *interf= ace, INIT_DELAYED_WORK(&dev->free_framebuffer_work, ufx_free_framebuffer_work); =20 - INIT_LIST_HEAD(&info->modelist); - retval =3D ufx_reg_read(dev, 0x3000, &id_rev); check_warn_goto_error(retval, "error %d reading 0x3000 register from devi= ce", retval); dev_dbg(dev->gdev, "ID_REV register value 0x%08x", id_rev); diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index b9cdd02c1000..90f48b71fd8f 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -1426,7 +1426,7 @@ static ssize_t metrics_bytes_rendered_show(struct dev= ice *fbdev, struct device_attribute *a, char *buf) { struct fb_info *fb_info =3D dev_get_drvdata(fbdev); struct dlfb_data *dlfb =3D fb_info->par; - return snprintf(buf, PAGE_SIZE, "%u\n", + return sysfs_emit(buf, "%u\n", atomic_read(&dlfb->bytes_rendered)); } =20 @@ -1434,7 +1434,7 @@ static ssize_t metrics_bytes_identical_show(struct de= vice *fbdev, struct device_attribute *a, char *buf) { struct fb_info *fb_info =3D dev_get_drvdata(fbdev); struct dlfb_data *dlfb =3D fb_info->par; - return snprintf(buf, PAGE_SIZE, "%u\n", + return sysfs_emit(buf, "%u\n", atomic_read(&dlfb->bytes_identical)); } =20 @@ -1442,7 +1442,7 @@ static ssize_t metrics_bytes_sent_show(struct device = *fbdev, struct device_attribute *a, char *buf) { struct fb_info *fb_info =3D dev_get_drvdata(fbdev); struct dlfb_data *dlfb =3D fb_info->par; - return snprintf(buf, PAGE_SIZE, "%u\n", + return sysfs_emit(buf, "%u\n", atomic_read(&dlfb->bytes_sent)); } =20 @@ -1450,7 +1450,7 @@ static ssize_t metrics_cpu_kcycles_used_show(struct d= evice *fbdev, struct device_attribute *a, char *buf) { struct fb_info *fb_info =3D dev_get_drvdata(fbdev); struct dlfb_data *dlfb =3D fb_info->par; - return snprintf(buf, PAGE_SIZE, "%u\n", + return sysfs_emit(buf, "%u\n", atomic_read(&dlfb->cpu_kcycles_used)); } =20 diff --git a/drivers/video/fbdev/w100fb.c b/drivers/video/fbdev/w100fb.c index d96ab28f8ce4..4e641a780726 100644 --- a/drivers/video/fbdev/w100fb.c +++ b/drivers/video/fbdev/w100fb.c @@ -770,12 +770,18 @@ static int w100fb_probe(struct platform_device *pdev) fb_dealloc_cmap(&info->cmap); kfree(info->pseudo_palette); } - if (remapped_fbuf !=3D NULL) + if (remapped_fbuf !=3D NULL) { iounmap(remapped_fbuf); - if (remapped_regs !=3D NULL) + remapped_fbuf =3D NULL; + } + if (remapped_regs !=3D NULL) { iounmap(remapped_regs); - if (remapped_base !=3D NULL) + remapped_regs =3D NULL; + } + if (remapped_base !=3D NULL) { iounmap(remapped_base); + remapped_base =3D NULL; + } if (info) framebuffer_release(info); return err; @@ -795,8 +801,11 @@ static int w100fb_remove(struct platform_device *pdev) fb_dealloc_cmap(&info->cmap); =20 iounmap(remapped_base); + remapped_base =3D NULL; iounmap(remapped_regs); + remapped_regs =3D NULL; iounmap(remapped_fbuf); + remapped_fbuf =3D NULL; =20 framebuffer_release(info); =20 diff --git a/drivers/virt/acrn/hsm.c b/drivers/virt/acrn/hsm.c index 5419794fccf1..423ea888d79a 100644 --- a/drivers/virt/acrn/hsm.c +++ b/drivers/virt/acrn/hsm.c @@ -136,8 +136,10 @@ static long acrn_dev_ioctl(struct file *filp, unsigned= int cmd, if (IS_ERR(vm_param)) return PTR_ERR(vm_param); =20 - if ((vm_param->reserved0 | vm_param->reserved1) !=3D 0) + if ((vm_param->reserved0 | vm_param->reserved1) !=3D 0) { + kfree(vm_param); return -EINVAL; + } =20 vm =3D acrn_vm_create(vm, vm_param); if (!vm) { @@ -182,21 +184,29 @@ static long acrn_dev_ioctl(struct file *filp, unsigne= d int cmd, return PTR_ERR(cpu_regs); =20 for (i =3D 0; i < ARRAY_SIZE(cpu_regs->reserved); i++) - if (cpu_regs->reserved[i]) + if (cpu_regs->reserved[i]) { + kfree(cpu_regs); return -EINVAL; + } =20 for (i =3D 0; i < ARRAY_SIZE(cpu_regs->vcpu_regs.reserved_32); i++) - if (cpu_regs->vcpu_regs.reserved_32[i]) + if (cpu_regs->vcpu_regs.reserved_32[i]) { + kfree(cpu_regs); return -EINVAL; + } =20 for (i =3D 0; i < ARRAY_SIZE(cpu_regs->vcpu_regs.reserved_64); i++) - if (cpu_regs->vcpu_regs.reserved_64[i]) + if (cpu_regs->vcpu_regs.reserved_64[i]) { + kfree(cpu_regs); return -EINVAL; + } =20 for (i =3D 0; i < ARRAY_SIZE(cpu_regs->vcpu_regs.gdt.reserved); i++) if (cpu_regs->vcpu_regs.gdt.reserved[i] | - cpu_regs->vcpu_regs.idt.reserved[i]) + cpu_regs->vcpu_regs.idt.reserved[i]) { + kfree(cpu_regs); return -EINVAL; + } =20 ret =3D hcall_set_vcpu_regs(vm->vmid, virt_to_phys(cpu_regs)); if (ret < 0) diff --git a/drivers/virt/acrn/mm.c b/drivers/virt/acrn/mm.c index c4f2e15c8a2b..3b1b1e7a844b 100644 --- a/drivers/virt/acrn/mm.c +++ b/drivers/virt/acrn/mm.c @@ -162,10 +162,34 @@ int acrn_vm_ram_map(struct acrn_vm *vm, struct acrn_v= m_memmap *memmap) void *remap_vaddr; int ret, pinned; u64 user_vm_pa; + unsigned long pfn; + struct vm_area_struct *vma; =20 if (!vm || !memmap) return -EINVAL; =20 + mmap_read_lock(current->mm); + vma =3D vma_lookup(current->mm, memmap->vma_base); + if (vma && ((vma->vm_flags & VM_PFNMAP) !=3D 0)) { + if ((memmap->vma_base + memmap->len) > vma->vm_end) { + mmap_read_unlock(current->mm); + return -EINVAL; + } + + ret =3D follow_pfn(vma, memmap->vma_base, &pfn); + mmap_read_unlock(current->mm); + if (ret < 0) { + dev_dbg(acrn_dev.this_device, + "Failed to lookup PFN at VMA:%pK.\n", (void *)memmap->vma_base); + return ret; + } + + return acrn_mm_region_add(vm, memmap->user_vm_pa, + PFN_PHYS(pfn), memmap->len, + ACRN_MEM_TYPE_WB, memmap->attr); + } + mmap_read_unlock(current->mm); + /* Get the page number of the map region */ nr_pages =3D memmap->len >> PAGE_SHIFT; pages =3D vzalloc(nr_pages * sizeof(struct page *)); diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index c2b733ef95b0..c7dc7a9a6b06 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -504,8 +504,9 @@ int virtio_device_restore(struct virtio_device *dev) goto err; } =20 - /* Finally, tell the device we're all set */ - virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); + /* If restore didn't do it, mark device DRIVER_OK ourselves. */ + if (!(dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK)) + virtio_device_ready(dev); =20 virtio_config_enable(dev); =20 diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci= _common.c index fdbde1db5ec5..d724f676608b 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -24,46 +24,17 @@ MODULE_PARM_DESC(force_legacy, "Force legacy mode for transitional virtio 1 devices"); #endif =20 -/* disable irq handlers */ -void vp_disable_cbs(struct virtio_device *vdev) +/* wait for pending irq handlers */ +void vp_synchronize_vectors(struct virtio_device *vdev) { struct virtio_pci_device *vp_dev =3D to_vp_device(vdev); int i; =20 - if (vp_dev->intx_enabled) { - /* - * The below synchronize() guarantees that any - * interrupt for this line arriving after - * synchronize_irq() has completed is guaranteed to see - * intx_soft_enabled =3D=3D false. - */ - WRITE_ONCE(vp_dev->intx_soft_enabled, false); + if (vp_dev->intx_enabled) synchronize_irq(vp_dev->pci_dev->irq); - } - - for (i =3D 0; i < vp_dev->msix_vectors; ++i) - disable_irq(pci_irq_vector(vp_dev->pci_dev, i)); -} - -/* enable irq handlers */ -void vp_enable_cbs(struct virtio_device *vdev) -{ - struct virtio_pci_device *vp_dev =3D to_vp_device(vdev); - int i; - - if (vp_dev->intx_enabled) { - disable_irq(vp_dev->pci_dev->irq); - /* - * The above disable_irq() provides TSO ordering and - * as such promotes the below store to store-release. - */ - WRITE_ONCE(vp_dev->intx_soft_enabled, true); - enable_irq(vp_dev->pci_dev->irq); - return; - } =20 for (i =3D 0; i < vp_dev->msix_vectors; ++i) - enable_irq(pci_irq_vector(vp_dev->pci_dev, i)); + synchronize_irq(pci_irq_vector(vp_dev->pci_dev, i)); } =20 /* the notify function used when creating a virt queue */ @@ -113,9 +84,6 @@ static irqreturn_t vp_interrupt(int irq, void *opaque) struct virtio_pci_device *vp_dev =3D opaque; u8 isr; =20 - if (!READ_ONCE(vp_dev->intx_soft_enabled)) - return IRQ_NONE; - /* reading the ISR has the effect of also clearing it so it's very * important to save off the value. */ isr =3D ioread8(vp_dev->isr); @@ -173,8 +141,7 @@ static int vp_request_msix_vectors(struct virtio_device= *vdev, int nvectors, snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names, "%s-config", name); err =3D request_irq(pci_irq_vector(vp_dev->pci_dev, v), - vp_config_changed, IRQF_NO_AUTOEN, - vp_dev->msix_names[v], + vp_config_changed, 0, vp_dev->msix_names[v], vp_dev); if (err) goto error; @@ -193,8 +160,7 @@ static int vp_request_msix_vectors(struct virtio_device= *vdev, int nvectors, snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names, "%s-virtqueues", name); err =3D request_irq(pci_irq_vector(vp_dev->pci_dev, v), - vp_vring_interrupt, IRQF_NO_AUTOEN, - vp_dev->msix_names[v], + vp_vring_interrupt, 0, vp_dev->msix_names[v], vp_dev); if (err) goto error; @@ -371,7 +337,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev,= unsigned nvqs, "%s-%s", dev_name(&vp_dev->vdev.dev), names[i]); err =3D request_irq(pci_irq_vector(vp_dev->pci_dev, msix_vec), - vring_interrupt, IRQF_NO_AUTOEN, + vring_interrupt, 0, vp_dev->msix_names[msix_vec], vqs[i]); if (err) diff --git a/drivers/virtio/virtio_pci_common.h b/drivers/virtio/virtio_pci= _common.h index 23f6c5c678d5..eb17a29fc7ef 100644 --- a/drivers/virtio/virtio_pci_common.h +++ b/drivers/virtio/virtio_pci_common.h @@ -63,7 +63,6 @@ struct virtio_pci_device { /* MSI-X support */ int msix_enabled; int intx_enabled; - bool intx_soft_enabled; cpumask_var_t *msix_affinity_masks; /* Name strings for interrupts. This size should be enough, * and I'm too lazy to allocate each name separately. */ @@ -102,10 +101,8 @@ static struct virtio_pci_device *to_vp_device(struct v= irtio_device *vdev) return container_of(vdev, struct virtio_pci_device, vdev); } =20 -/* disable irq handlers */ -void vp_disable_cbs(struct virtio_device *vdev); -/* enable irq handlers */ -void vp_enable_cbs(struct virtio_device *vdev); +/* wait for pending irq handlers */ +void vp_synchronize_vectors(struct virtio_device *vdev); /* the notify function used when creating a virt queue */ bool vp_notify(struct virtqueue *vq); /* the config->del_vqs() implementation */ diff --git a/drivers/virtio/virtio_pci_legacy.c b/drivers/virtio/virtio_pci= _legacy.c index b3f8128b7983..82eb437ad920 100644 --- a/drivers/virtio/virtio_pci_legacy.c +++ b/drivers/virtio/virtio_pci_legacy.c @@ -98,8 +98,8 @@ static void vp_reset(struct virtio_device *vdev) /* Flush out the status write, and flush in device writes, * including MSi-X interrupts, if any. */ vp_legacy_get_status(&vp_dev->ldev); - /* Disable VQ/configuration callbacks. */ - vp_disable_cbs(vdev); + /* Flush pending VQ/configuration callbacks. */ + vp_synchronize_vectors(vdev); } =20 static u16 vp_config_vector(struct virtio_pci_device *vp_dev, u16 vector) @@ -185,7 +185,6 @@ static void del_vq(struct virtio_pci_vq_info *info) } =20 static const struct virtio_config_ops virtio_pci_config_ops =3D { - .enable_cbs =3D vp_enable_cbs, .get =3D vp_get, .set =3D vp_set, .get_status =3D vp_get_status, diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci= _modern.c index 5455bc041fb6..30654d3a0b41 100644 --- a/drivers/virtio/virtio_pci_modern.c +++ b/drivers/virtio/virtio_pci_modern.c @@ -172,8 +172,8 @@ static void vp_reset(struct virtio_device *vdev) */ while (vp_modern_get_status(mdev)) msleep(1); - /* Disable VQ/configuration callbacks. */ - vp_disable_cbs(vdev); + /* Flush pending VQ/configuration callbacks. */ + vp_synchronize_vectors(vdev); } =20 static u16 vp_config_vector(struct virtio_pci_device *vp_dev, u16 vector) @@ -380,7 +380,6 @@ static bool vp_get_shm_region(struct virtio_device *vde= v, } =20 static const struct virtio_config_ops virtio_pci_config_nodev_ops =3D { - .enable_cbs =3D vp_enable_cbs, .get =3D NULL, .set =3D NULL, .generation =3D vp_generation, @@ -398,7 +397,6 @@ static const struct virtio_config_ops virtio_pci_config= _nodev_ops =3D { }; =20 static const struct virtio_config_ops virtio_pci_config_ops =3D { - .enable_cbs =3D vp_enable_cbs, .get =3D vp_get, .set =3D vp_set, .generation =3D vp_generation, diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c index 117bc2a8eb0a..db843f825860 100644 --- a/drivers/watchdog/rti_wdt.c +++ b/drivers/watchdog/rti_wdt.c @@ -228,6 +228,7 @@ static int rti_wdt_probe(struct platform_device *pdev) ret =3D pm_runtime_get_sync(dev); if (ret) { pm_runtime_put_noidle(dev); + pm_runtime_disable(&pdev->dev); return dev_err_probe(dev, ret, "runtime pm failed\n"); } =20 diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index d19762dc90fe..caf58b185a8b 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -170,8 +170,8 @@ static int padzero(unsigned long elf_bss) =20 static int create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec, - unsigned long load_addr, unsigned long interp_load_addr, - unsigned long e_entry) + unsigned long interp_load_addr, + unsigned long e_entry, unsigned long phdr_addr) { struct mm_struct *mm =3D current->mm; unsigned long p =3D bprm->p; @@ -257,7 +257,7 @@ create_elf_tables(struct linux_binprm *bprm, const stru= ct elfhdr *exec, NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP); NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE); NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); - NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff); + NEW_AUX_ENT(AT_PHDR, phdr_addr); NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); NEW_AUX_ENT(AT_PHNUM, exec->e_phnum); NEW_AUX_ENT(AT_BASE, interp_load_addr); @@ -823,7 +823,7 @@ static int parse_elf_properties(struct file *f, const s= truct elf_phdr *phdr, static int load_elf_binary(struct linux_binprm *bprm) { struct file *interpreter =3D NULL; /* to shut gcc up */ - unsigned long load_addr =3D 0, load_bias =3D 0; + unsigned long load_addr, load_bias =3D 0, phdr_addr =3D 0; int load_addr_set =3D 0; unsigned long error; struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata =3D NULL; @@ -1180,6 +1180,17 @@ static int load_elf_binary(struct linux_binprm *bprm) reloc_func_desc =3D load_bias; } } + + /* + * Figure out which segment in the file contains the Program + * Header table, and map to the associated memory address. + */ + if (elf_ppnt->p_offset <=3D elf_ex->e_phoff && + elf_ex->e_phoff < elf_ppnt->p_offset + elf_ppnt->p_filesz) { + phdr_addr =3D elf_ex->e_phoff - elf_ppnt->p_offset + + elf_ppnt->p_vaddr; + } + k =3D elf_ppnt->p_vaddr; if ((elf_ppnt->p_flags & PF_X) && k < start_code) start_code =3D k; @@ -1215,6 +1226,7 @@ static int load_elf_binary(struct linux_binprm *bprm) } =20 e_entry =3D elf_ex->e_entry + load_bias; + phdr_addr +=3D load_bias; elf_bss +=3D load_bias; elf_brk +=3D load_bias; start_code +=3D load_bias; @@ -1278,8 +1290,8 @@ static int load_elf_binary(struct linux_binprm *bprm) goto out; #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ =20 - retval =3D create_elf_tables(bprm, elf_ex, - load_addr, interp_load_addr, e_entry); + retval =3D create_elf_tables(bprm, elf_ex, interp_load_addr, + e_entry, phdr_addr); if (retval < 0) goto out; =20 @@ -1630,17 +1642,16 @@ static void fill_siginfo_note(struct memelfnote *no= te, user_siginfo_t *csigdata, * long file_ofs * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL... */ -static int fill_files_note(struct memelfnote *note) +static int fill_files_note(struct memelfnote *note, struct coredump_params= *cprm) { - struct mm_struct *mm =3D current->mm; - struct vm_area_struct *vma; unsigned count, size, names_ofs, remaining, n; user_long_t *data; user_long_t *start_end_ofs; char *name_base, *name_curpos; + int i; =20 /* *Estimated* file count and total data size needed */ - count =3D mm->map_count; + count =3D cprm->vma_count; if (count > UINT_MAX / 64) return -EINVAL; size =3D count * 64; @@ -1662,11 +1673,12 @@ static int fill_files_note(struct memelfnote *note) name_base =3D name_curpos =3D ((char *)data) + names_ofs; remaining =3D size - names_ofs; count =3D 0; - for (vma =3D mm->mmap; vma !=3D NULL; vma =3D vma->vm_next) { + for (i =3D 0; i < cprm->vma_count; i++) { + struct core_vma_metadata *m =3D &cprm->vma_meta[i]; struct file *file; const char *filename; =20 - file =3D vma->vm_file; + file =3D m->file; if (!file) continue; filename =3D file_path(file, name_curpos, remaining); @@ -1686,9 +1698,9 @@ static int fill_files_note(struct memelfnote *note) memmove(name_curpos, filename, n); name_curpos +=3D n; =20 - *start_end_ofs++ =3D vma->vm_start; - *start_end_ofs++ =3D vma->vm_end; - *start_end_ofs++ =3D vma->vm_pgoff; + *start_end_ofs++ =3D m->start; + *start_end_ofs++ =3D m->end; + *start_end_ofs++ =3D m->pgoff; count++; } =20 @@ -1699,7 +1711,7 @@ static int fill_files_note(struct memelfnote *note) * Count usually is less than mm->map_count, * we need to move filenames down. */ - n =3D mm->map_count - count; + n =3D cprm->vma_count - count; if (n !=3D 0) { unsigned shift_bytes =3D n * 3 * sizeof(data[0]); memmove(name_base - shift_bytes, name_base, @@ -1811,7 +1823,7 @@ static int fill_thread_core_info(struct elf_thread_co= re_info *t, =20 static int fill_note_info(struct elfhdr *elf, int phdrs, struct elf_note_info *info, - const kernel_siginfo_t *siginfo, struct pt_regs *regs) + struct coredump_params *cprm) { struct task_struct *dump_task =3D current; const struct user_regset_view *view =3D task_user_regset_view(dump_task); @@ -1883,7 +1895,7 @@ static int fill_note_info(struct elfhdr *elf, int phd= rs, * Now fill in each thread's information. */ for (t =3D info->thread; t !=3D NULL; t =3D t->next) - if (!fill_thread_core_info(t, view, siginfo->si_signo, &info->size)) + if (!fill_thread_core_info(t, view, cprm->siginfo->si_signo, &info->size= )) return 0; =20 /* @@ -1892,13 +1904,13 @@ static int fill_note_info(struct elfhdr *elf, int p= hdrs, fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm); info->size +=3D notesize(&info->psinfo); =20 - fill_siginfo_note(&info->signote, &info->csigdata, siginfo); + fill_siginfo_note(&info->signote, &info->csigdata, cprm->siginfo); info->size +=3D notesize(&info->signote); =20 fill_auxv_note(&info->auxv, current->mm); info->size +=3D notesize(&info->auxv); =20 - if (fill_files_note(&info->files) =3D=3D 0) + if (fill_files_note(&info->files, cprm) =3D=3D 0) info->size +=3D notesize(&info->files); =20 return 1; @@ -2040,7 +2052,7 @@ static int elf_note_info_init(struct elf_note_info *i= nfo) =20 static int fill_note_info(struct elfhdr *elf, int phdrs, struct elf_note_info *info, - const kernel_siginfo_t *siginfo, struct pt_regs *regs) + struct coredump_params *cprm) { struct core_thread *ct; struct elf_thread_status *ets; @@ -2061,13 +2073,13 @@ static int fill_note_info(struct elfhdr *elf, int p= hdrs, list_for_each_entry(ets, &info->thread_list, list) { int sz; =20 - sz =3D elf_dump_thread_status(siginfo->si_signo, ets); + sz =3D elf_dump_thread_status(cprm->siginfo->si_signo, ets); info->thread_status_size +=3D sz; } /* now collect the dump for the current */ memset(info->prstatus, 0, sizeof(*info->prstatus)); - fill_prstatus(&info->prstatus->common, current, siginfo->si_signo); - elf_core_copy_regs(&info->prstatus->pr_reg, regs); + fill_prstatus(&info->prstatus->common, current, cprm->siginfo->si_signo); + elf_core_copy_regs(&info->prstatus->pr_reg, cprm->regs); =20 /* Set up header */ fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS); @@ -2083,18 +2095,18 @@ static int fill_note_info(struct elfhdr *elf, int p= hdrs, fill_note(info->notes + 1, "CORE", NT_PRPSINFO, sizeof(*info->psinfo), info->psinfo); =20 - fill_siginfo_note(info->notes + 2, &info->csigdata, siginfo); + fill_siginfo_note(info->notes + 2, &info->csigdata, cprm->siginfo); fill_auxv_note(info->notes + 3, current->mm); info->numnote =3D 4; =20 - if (fill_files_note(info->notes + info->numnote) =3D=3D 0) { + if (fill_files_note(info->notes + info->numnote, cprm) =3D=3D 0) { info->notes_files =3D info->notes + info->numnote; info->numnote++; } =20 /* Try to dump the FPU. */ - info->prstatus->pr_fpvalid =3D elf_core_copy_task_fpregs(current, regs, - info->fpu); + info->prstatus->pr_fpvalid =3D + elf_core_copy_task_fpregs(current, cprm->regs, info->fpu); if (info->prstatus->pr_fpvalid) fill_note(info->notes + info->numnote++, "CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu); @@ -2180,8 +2192,7 @@ static void fill_extnum_info(struct elfhdr *elf, stru= ct elf_shdr *shdr4extnum, static int elf_core_dump(struct coredump_params *cprm) { int has_dumped =3D 0; - int vma_count, segs, i; - size_t vma_data_size; + int segs, i; struct elfhdr elf; loff_t offset =3D 0, dataoff; struct elf_note_info info =3D { }; @@ -2189,16 +2200,12 @@ static int elf_core_dump(struct coredump_params *cp= rm) struct elf_shdr *shdr4extnum =3D NULL; Elf_Half e_phnum; elf_addr_t e_shoff; - struct core_vma_metadata *vma_meta; - - if (dump_vma_snapshot(cprm, &vma_count, &vma_meta, &vma_data_size)) - return 0; =20 /* * The number of segs are recored into ELF header as 16bit value. * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here. */ - segs =3D vma_count + elf_core_extra_phdrs(); + segs =3D cprm->vma_count + elf_core_extra_phdrs(); =20 /* for notes section */ segs++; @@ -2212,7 +2219,7 @@ static int elf_core_dump(struct coredump_params *cprm) * Collect all the non-memory information about the process for the * notes. This also sets up the file header. */ - if (!fill_note_info(&elf, e_phnum, &info, cprm->siginfo, cprm->regs)) + if (!fill_note_info(&elf, e_phnum, &info, cprm)) goto end_coredump; =20 has_dumped =3D 1; @@ -2237,7 +2244,7 @@ static int elf_core_dump(struct coredump_params *cprm) =20 dataoff =3D offset =3D roundup(offset, ELF_EXEC_PAGESIZE); =20 - offset +=3D vma_data_size; + offset +=3D cprm->vma_data_size; offset +=3D elf_core_extra_data_size(); e_shoff =3D offset; =20 @@ -2257,8 +2264,8 @@ static int elf_core_dump(struct coredump_params *cprm) goto end_coredump; =20 /* Write program headers for segments dump */ - for (i =3D 0; i < vma_count; i++) { - struct core_vma_metadata *meta =3D vma_meta + i; + for (i =3D 0; i < cprm->vma_count; i++) { + struct core_vma_metadata *meta =3D cprm->vma_meta + i; struct elf_phdr phdr; =20 phdr.p_type =3D PT_LOAD; @@ -2295,8 +2302,8 @@ static int elf_core_dump(struct coredump_params *cprm) /* Align to page */ dump_skip_to(cprm, dataoff); =20 - for (i =3D 0; i < vma_count; i++) { - struct core_vma_metadata *meta =3D vma_meta + i; + for (i =3D 0; i < cprm->vma_count; i++) { + struct core_vma_metadata *meta =3D cprm->vma_meta + i; =20 if (!dump_user_range(cprm, meta->start, meta->dump_size)) goto end_coredump; @@ -2313,7 +2320,6 @@ static int elf_core_dump(struct coredump_params *cprm) end_coredump: free_note_info(&info); kfree(shdr4extnum); - kvfree(vma_meta); kfree(phdr4note); return has_dumped; } diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index c6f588dc4a9d..1a25536b0120 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1465,7 +1465,7 @@ static bool elf_fdpic_dump_segments(struct coredump_p= arams *cprm, static int elf_fdpic_core_dump(struct coredump_params *cprm) { int has_dumped =3D 0; - int vma_count, segs; + int segs; int i; struct elfhdr *elf =3D NULL; loff_t offset =3D 0, dataoff; @@ -1480,8 +1480,6 @@ static int elf_fdpic_core_dump(struct coredump_params= *cprm) elf_addr_t e_shoff; struct core_thread *ct; struct elf_thread_status *tmp; - struct core_vma_metadata *vma_meta =3D NULL; - size_t vma_data_size; =20 /* alloc memory for large data structures: too large to be on stack */ elf =3D kmalloc(sizeof(*elf), GFP_KERNEL); @@ -1491,9 +1489,6 @@ static int elf_fdpic_core_dump(struct coredump_params= *cprm) if (!psinfo) goto end_coredump; =20 - if (dump_vma_snapshot(cprm, &vma_count, &vma_meta, &vma_data_size)) - goto end_coredump; - for (ct =3D current->signal->core_state->dumper.next; ct; ct =3D ct->next) { tmp =3D elf_dump_thread_status(cprm->siginfo->si_signo, @@ -1513,7 +1508,7 @@ static int elf_fdpic_core_dump(struct coredump_params= *cprm) tmp->next =3D thread_list; thread_list =3D tmp; =20 - segs =3D vma_count + elf_core_extra_phdrs(); + segs =3D cprm->vma_count + elf_core_extra_phdrs(); =20 /* for notes section */ segs++; @@ -1558,7 +1553,7 @@ static int elf_fdpic_core_dump(struct coredump_params= *cprm) /* Page-align dumped data */ dataoff =3D offset =3D roundup(offset, ELF_EXEC_PAGESIZE); =20 - offset +=3D vma_data_size; + offset +=3D cprm->vma_data_size; offset +=3D elf_core_extra_data_size(); e_shoff =3D offset; =20 @@ -1578,8 +1573,8 @@ static int elf_fdpic_core_dump(struct coredump_params= *cprm) goto end_coredump; =20 /* write program headers for segments dump */ - for (i =3D 0; i < vma_count; i++) { - struct core_vma_metadata *meta =3D vma_meta + i; + for (i =3D 0; i < cprm->vma_count; i++) { + struct core_vma_metadata *meta =3D cprm->vma_meta + i; struct elf_phdr phdr; size_t sz; =20 @@ -1628,7 +1623,7 @@ static int elf_fdpic_core_dump(struct coredump_params= *cprm) =20 dump_skip_to(cprm, dataoff); =20 - if (!elf_fdpic_dump_segments(cprm, vma_meta, vma_count)) + if (!elf_fdpic_dump_segments(cprm, cprm->vma_meta, cprm->vma_count)) goto end_coredump; =20 if (!elf_core_write_extra_data(cprm)) @@ -1652,7 +1647,6 @@ static int elf_fdpic_core_dump(struct coredump_params= *cprm) thread_list =3D thread_list->next; kfree(tmp); } - kvfree(vma_meta); kfree(phdr4note); kfree(elf); kfree(psinfo); diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c index 05c606fb3968..398904be0f41 100644 --- a/fs/btrfs/block-group.c +++ b/fs/btrfs/block-group.c @@ -1521,8 +1521,12 @@ void btrfs_reclaim_bgs_work(struct work_struct *work) if (!test_bit(BTRFS_FS_OPEN, &fs_info->flags)) return; =20 - if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_BALANCE)) + sb_start_write(fs_info->sb); + + if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_BALANCE)) { + sb_end_write(fs_info->sb); return; + } =20 /* * Long running balances can keep us blocked here for eternity, so @@ -1530,6 +1534,7 @@ void btrfs_reclaim_bgs_work(struct work_struct *work) */ if (!mutex_trylock(&fs_info->reclaim_bgs_lock)) { btrfs_exclop_finish(fs_info); + sb_end_write(fs_info->sb); return; } =20 @@ -1604,6 +1609,7 @@ void btrfs_reclaim_bgs_work(struct work_struct *work) spin_unlock(&fs_info->unused_bgs_lock); mutex_unlock(&fs_info->reclaim_bgs_lock); btrfs_exclop_finish(fs_info); + sb_end_write(fs_info->sb); } =20 void btrfs_reclaim_bgs(struct btrfs_fs_info *fs_info) diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index 32da97c3c19d..66d6a414b2ca 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -807,7 +807,7 @@ blk_status_t btrfs_submit_compressed_read(struct inode = *inode, struct bio *bio, u64 em_len; u64 em_start; struct extent_map *em; - blk_status_t ret =3D BLK_STS_RESOURCE; + blk_status_t ret; int faili =3D 0; u8 *sums; =20 @@ -820,14 +820,18 @@ blk_status_t btrfs_submit_compressed_read(struct inod= e *inode, struct bio *bio, read_lock(&em_tree->lock); em =3D lookup_extent_mapping(em_tree, file_offset, fs_info->sectorsize); read_unlock(&em_tree->lock); - if (!em) - return BLK_STS_IOERR; + if (!em) { + ret =3D BLK_STS_IOERR; + goto out; + } =20 ASSERT(em->compress_type !=3D BTRFS_COMPRESS_NONE); compressed_len =3D em->block_len; cb =3D kmalloc(compressed_bio_size(fs_info, compressed_len), GFP_NOFS); - if (!cb) + if (!cb) { + ret =3D BLK_STS_RESOURCE; goto out; + } =20 refcount_set(&cb->pending_sectors, compressed_len >> fs_info->sectorsize_= bits); cb->errors =3D 0; @@ -850,8 +854,10 @@ blk_status_t btrfs_submit_compressed_read(struct inode= *inode, struct bio *bio, nr_pages =3D DIV_ROUND_UP(compressed_len, PAGE_SIZE); cb->compressed_pages =3D kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS); - if (!cb->compressed_pages) + if (!cb->compressed_pages) { + ret =3D BLK_STS_RESOURCE; goto fail1; + } =20 for (pg_index =3D 0; pg_index < nr_pages; pg_index++) { cb->compressed_pages[pg_index] =3D alloc_page(GFP_NOFS); @@ -937,7 +943,7 @@ blk_status_t btrfs_submit_compressed_read(struct inode = *inode, struct bio *bio, comp_bio =3D NULL; } } - return 0; + return BLK_STS_OK; =20 fail2: while (faili >=3D 0) { @@ -950,6 +956,8 @@ blk_status_t btrfs_submit_compressed_read(struct inode = *inode, struct bio *bio, kfree(cb); out: free_extent_map(em); + bio->bi_status =3D ret; + bio_endio(bio); return ret; finish_cb: if (comp_bio) { diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 098002533110..aab385585188 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -441,17 +441,31 @@ static int csum_one_extent_buffer(struct extent_buffe= r *eb) else ret =3D btrfs_check_leaf_full(eb); =20 - if (ret < 0) { - btrfs_print_tree(eb, 0); + if (ret < 0) + goto error; + + /* + * Also check the generation, the eb reached here must be newer than + * last committed. Or something seriously wrong happened. + */ + if (unlikely(btrfs_header_generation(eb) <=3D fs_info->last_trans_committ= ed)) { + ret =3D -EUCLEAN; btrfs_err(fs_info, - "block=3D%llu write time tree block corruption detected", - eb->start); - WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG)); - return ret; + "block=3D%llu bad generation, have %llu expect > %llu", + eb->start, btrfs_header_generation(eb), + fs_info->last_trans_committed); + goto error; } write_extent_buffer(eb, result, 0, fs_info->csum_size); =20 return 0; + +error: + btrfs_print_tree(eb, 0); + btrfs_err(fs_info, "block=3D%llu write time tree block corruption detecte= d", + eb->start); + WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG)); + return ret; } =20 /* Checksum all dirty extent buffers in one bio_vec */ diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 5512d7028091..ced0195f3390 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2640,7 +2640,6 @@ int btrfs_repair_one_sector(struct inode *inode, const int icsum =3D bio_offset >> fs_info->sectorsize_bits; struct bio *repair_bio; struct btrfs_bio *repair_bbio; - blk_status_t status; =20 btrfs_debug(fs_info, "repair read error: read error at %llu", start); @@ -2679,13 +2678,13 @@ int btrfs_repair_one_sector(struct inode *inode, "repair read error: submitting new read to mirror %d", failrec->this_mirror); =20 - status =3D submit_bio_hook(inode, repair_bio, failrec->this_mirror, - failrec->bio_flags); - if (status) { - free_io_failure(failure_tree, tree, failrec); - bio_put(repair_bio); - } - return blk_status_to_errno(status); + /* + * At this point we have a bio, so any errors from submit_bio_hook() + * will be handled by the endio on the repair_bio, so we can't return an + * error here. + */ + submit_bio_hook(inode, repair_bio, failrec->this_mirror, failrec->bio_fla= gs); + return BLK_STS_OK; } =20 static void end_page_read(struct page *page, bool uptodate, u64 start, u32= len) @@ -4800,11 +4799,12 @@ static int submit_eb_page(struct page *page, struct= writeback_control *wbc, return ret; } if (cache) { - /* Impiles write in zoned mode */ - btrfs_put_block_group(cache); - /* Mark the last eb in a block group */ + /* + * Implies write in zoned mode. Mark the last eb in a block group. + */ if (cache->seq_zone && eb->start + eb->len =3D=3D cache->zone_capacity) set_bit(EXTENT_BUFFER_ZONE_FINISH, &eb->bflags); + btrfs_put_block_group(cache); } ret =3D write_one_eb(eb, wbc, epd); free_extent_buffer(eb); diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index d1cbb64a78f3..a68d9cab12ea 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -303,7 +303,7 @@ static int search_csum_tree(struct btrfs_fs_info *fs_in= fo, read_extent_buffer(path->nodes[0], dst, (unsigned long)item, ret * csum_size); out: - if (ret =3D=3D -ENOENT) + if (ret =3D=3D -ENOENT || ret =3D=3D -EFBIG) ret =3D 0; return ret; } @@ -366,6 +366,7 @@ blk_status_t btrfs_lookup_bio_sums(struct inode *inode,= struct bio *bio, u8 *dst { struct btrfs_fs_info *fs_info =3D btrfs_sb(inode->i_sb); struct extent_io_tree *io_tree =3D &BTRFS_I(inode)->io_tree; + struct btrfs_bio *bbio =3D NULL; struct btrfs_path *path; const u32 sectorsize =3D fs_info->sectorsize; const u32 csum_size =3D fs_info->csum_size; @@ -375,6 +376,7 @@ blk_status_t btrfs_lookup_bio_sums(struct inode *inode,= struct bio *bio, u8 *dst u8 *csum; const unsigned int nblocks =3D orig_len >> fs_info->sectorsize_bits; int count =3D 0; + blk_status_t ret =3D BLK_STS_OK; =20 if (!fs_info->csum_root || (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM= )) return BLK_STS_OK; @@ -397,7 +399,7 @@ blk_status_t btrfs_lookup_bio_sums(struct inode *inode,= struct bio *bio, u8 *dst return BLK_STS_RESOURCE; =20 if (!dst) { - struct btrfs_bio *bbio =3D btrfs_bio(bio); + bbio =3D btrfs_bio(bio); =20 if (nblocks * csum_size > BTRFS_BIO_INLINE_CSUM_SIZE) { bbio->csum =3D kmalloc_array(nblocks, csum_size, GFP_NOFS); @@ -453,21 +455,27 @@ blk_status_t btrfs_lookup_bio_sums(struct inode *inod= e, struct bio *bio, u8 *dst =20 count =3D search_csum_tree(fs_info, path, cur_disk_bytenr, search_len, csum_dst); - if (count <=3D 0) { - /* - * Either we hit a critical error or we didn't find - * the csum. - * Either way, we put zero into the csums dst, and skip - * to the next sector. - */ + if (count < 0) { + ret =3D errno_to_blk_status(count); + if (bbio) + btrfs_bio_free_csum(bbio); + break; + } + + /* + * We didn't find a csum for this range. We need to make sure + * we complain loudly about this, because we are not NODATASUM. + * + * However for the DATA_RELOC inode we could potentially be + * relocating data extents for a NODATASUM inode, so the inode + * itself won't be marked with NODATASUM, but the extent we're + * copying is in fact NODATASUM. If we don't find a csum we + * assume this is the case. + */ + if (count =3D=3D 0) { memset(csum_dst, 0, csum_size); count =3D 1; =20 - /* - * For data reloc inode, we need to mark the range - * NODATASUM so that balance won't report false csum - * error. - */ if (BTRFS_I(inode)->root->root_key.objectid =3D=3D BTRFS_DATA_RELOC_TREE_OBJECTID) { u64 file_offset; @@ -488,7 +496,7 @@ blk_status_t btrfs_lookup_bio_sums(struct inode *inode,= struct bio *bio, u8 *dst } =20 btrfs_free_path(path); - return BLK_STS_OK; + return ret; } =20 int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index cc957cce23a1..68f5a94c82b7 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -2536,10 +2536,15 @@ blk_status_t btrfs_submit_data_bio(struct inode *in= ode, struct bio *bio, goto out; =20 if (bio_flags & EXTENT_BIO_COMPRESSED) { + /* + * btrfs_submit_compressed_read will handle completing + * the bio if there were any errors, so just return + * here. + */ ret =3D btrfs_submit_compressed_read(inode, bio, mirror_num, bio_flags); - goto out; + goto out_no_endio; } else { /* * Lookup bio sums does extra checks around whether we @@ -2573,6 +2578,7 @@ blk_status_t btrfs_submit_data_bio(struct inode *inod= e, struct bio *bio, bio->bi_status =3D ret; bio_endio(bio); } +out_no_endio: return ret; } =20 diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c index e0f93b357548..157d72e330d6 100644 --- a/fs/btrfs/reflink.c +++ b/fs/btrfs/reflink.c @@ -505,8 +505,11 @@ static int btrfs_clone(struct inode *src, struct inode= *inode, */ ASSERT(key.offset =3D=3D 0); ASSERT(datal <=3D fs_info->sectorsize); - if (key.offset !=3D 0 || datal > fs_info->sectorsize) - return -EUCLEAN; + if (WARN_ON(key.offset !=3D 0) || + WARN_ON(datal > fs_info->sectorsize)) { + ret =3D -EUCLEAN; + goto out; + } =20 ret =3D clone_copy_inline_extent(inode, path, &new_key, drop_start, datal, size, diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c index 48d77f360a24..b1e6e06f2cbd 100644 --- a/fs/btrfs/space-info.c +++ b/fs/btrfs/space-info.c @@ -1059,7 +1059,6 @@ static void btrfs_preempt_reclaim_metadata_space(stru= ct work_struct *work) trans_rsv->reserved; if (block_rsv_size < space_info->bytes_may_use) delalloc_size =3D space_info->bytes_may_use - block_rsv_size; - spin_unlock(&space_info->lock); =20 /* * We don't want to include the global_rsv in our calculation, @@ -1090,6 +1089,8 @@ static void btrfs_preempt_reclaim_metadata_space(stru= ct work_struct *work) flush =3D FLUSH_DELAYED_REFS_NR; } =20 + spin_unlock(&space_info->lock); + /* * We don't want to reclaim everything, just a portion, so scale * down the to_reclaim by 1/4. If it takes us down to 0, diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 42391d4aeb11..683822b7b194 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -530,15 +530,48 @@ btrfs_get_bdev_and_sb(const char *device_path, fmode_= t flags, void *holder, return ret; } =20 -static bool device_path_matched(const char *path, struct btrfs_device *dev= ice) +/* + * Check if the device in the path matches the device in the given struct = device. + * + * Returns: + * true If it is the same device. + * false If it is not the same device or on error. + */ +static bool device_matched(const struct btrfs_device *device, const char *= path) { - int found; + char *device_name; + dev_t dev_old; + dev_t dev_new; + int ret; + + /* + * If we are looking for a device with the matching dev_t, then skip + * device without a name (a missing device). + */ + if (!device->name) + return false; + + device_name =3D kzalloc(BTRFS_PATH_NAME_MAX, GFP_KERNEL); + if (!device_name) + return false; =20 rcu_read_lock(); - found =3D strcmp(rcu_str_deref(device->name), path); + scnprintf(device_name, BTRFS_PATH_NAME_MAX, "%s", rcu_str_deref(device->n= ame)); rcu_read_unlock(); =20 - return found =3D=3D 0; + ret =3D lookup_bdev(device_name, &dev_old); + kfree(device_name); + if (ret) + return false; + + ret =3D lookup_bdev(path, &dev_new); + if (ret) + return false; + + if (dev_old =3D=3D dev_new) + return true; + + return false; } =20 /* @@ -571,9 +604,7 @@ static int btrfs_free_stale_devices(const char *path, &fs_devices->devices, dev_list) { if (skip_device && skip_device =3D=3D device) continue; - if (path && !device->name) - continue; - if (path && !device_path_matched(path, device)) + if (path && !device_matched(device, path)) continue; if (fs_devices->opened) { /* for an already deleted device return 0 */ @@ -8263,10 +8294,12 @@ static int relocating_repair_kthread(void *data) target =3D cache->start; btrfs_put_block_group(cache); =20 + sb_start_write(fs_info->sb); if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_BALANCE)) { btrfs_info(fs_info, "zoned: skip relocating block group %llu to repair: EBUSY", target); + sb_end_write(fs_info->sb); return -EBUSY; } =20 @@ -8294,6 +8327,7 @@ static int relocating_repair_kthread(void *data) btrfs_put_block_group(cache); mutex_unlock(&fs_info->reclaim_bgs_lock); btrfs_exclop_finish(fs_info); + sb_end_write(fs_info->sb); =20 return ret; } diff --git a/fs/buffer.c b/fs/buffer.c index 46bc589b7a03..d959b52f0d1a 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1235,16 +1235,18 @@ static void bh_lru_install(struct buffer_head *bh) int i; =20 check_irqs_on(); + bh_lru_lock(); + /* * the refcount of buffer_head in bh_lru prevents dropping the * attached page(i.e., try_to_free_buffers) so it could cause * failing page migration. * Skip putting upcoming bh into bh_lru until migration is done. */ - if (lru_cache_disabled()) + if (lru_cache_disabled()) { + bh_lru_unlock(); return; - - bh_lru_lock(); + } =20 b =3D this_cpu_ptr(&bh_lrus); for (i =3D 0; i < BH_LRU_SIZE; i++) { diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 99c51391a48d..02b762b7e3fd 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -209,6 +209,9 @@ cifs_read_super(struct super_block *sb) if (rc) goto out_no_root; /* tune readahead according to rsize if readahead size not set on mount */ + if (cifs_sb->ctx->rsize =3D=3D 0) + cifs_sb->ctx->rsize =3D + tcon->ses->server->ops->negotiate_rsize(tcon, cifs_sb->ctx); if (cifs_sb->ctx->rasize) sb->s_bdi->ra_pages =3D cifs_sb->ctx->rasize / PAGE_SIZE; else @@ -253,6 +256,9 @@ static void cifs_kill_sb(struct super_block *sb) struct cifs_sb_info *cifs_sb =3D CIFS_SB(sb); struct cifs_tcon *tcon; struct cached_fid *cfid; + struct rb_root *root =3D &cifs_sb->tlink_tree; + struct rb_node *node; + struct tcon_link *tlink; =20 /* * We ned to release all dentries for the cached directories @@ -262,16 +268,18 @@ static void cifs_kill_sb(struct super_block *sb) dput(cifs_sb->root); cifs_sb->root =3D NULL; } - tcon =3D cifs_sb_master_tcon(cifs_sb); - if (tcon) { + node =3D rb_first(root); + while (node !=3D NULL) { + tlink =3D rb_entry(node, struct tcon_link, tl_rbnode); + tcon =3D tlink_tcon(tlink); cfid =3D &tcon->crfid; mutex_lock(&cfid->fid_mutex); if (cfid->dentry) { - dput(cfid->dentry); cfid->dentry =3D NULL; } mutex_unlock(&cfid->fid_mutex); + node =3D rb_next(node); } =20 kill_anon_super(sb); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index fb69524a992b..ec9d225e255a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3401,6 +3401,9 @@ static int connect_dfs_target(struct mount_ctx *mnt_c= tx, const char *full_path, struct cifs_sb_info *cifs_sb =3D mnt_ctx->cifs_sb; char *oldmnt =3D cifs_sb->ctx->mount_options; =20 + cifs_dbg(FYI, "%s: full_path=3D%s ref_path=3D%s target=3D%s\n", __func__,= full_path, ref_path, + dfs_cache_get_tgt_name(tit)); + rc =3D dfs_cache_get_tgt_referral(ref_path, tit, &ref); if (rc) goto out; @@ -3499,13 +3502,18 @@ static int __follow_dfs_link(struct mount_ctx *mnt_= ctx) if (rc) goto out; =20 - /* Try all dfs link targets */ + /* Try all dfs link targets. If an I/O fails from currently connected DF= S target with an + * error other than STATUS_PATH_NOT_COVERED (-EREMOTE), then retry it fro= m other targets as + * specified in MS-DFSC "3.1.5.2 I/O Operation to Target Fails with an Er= ror Other Than + * STATUS_PATH_NOT_COVERED." + */ for (rc =3D -ENOENT, tit =3D dfs_cache_get_tgt_iterator(&tl); tit; tit =3D dfs_cache_get_next_tgt(&tl, tit)) { rc =3D connect_dfs_target(mnt_ctx, full_path, mnt_ctx->leaf_fullpath + 1= , tit); if (!rc) { rc =3D is_path_remote(mnt_ctx); - break; + if (!rc || rc =3D=3D -EREMOTE) + break; } } =20 @@ -3579,7 +3587,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct s= mb3_fs_context *ctx) goto error; =20 rc =3D is_path_remote(&mnt_ctx); - if (rc =3D=3D -EREMOTE) + if (rc) rc =3D follow_dfs_link(&mnt_ctx); if (rc) goto error; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 9fee3af83a73..abadc2f86dea 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -3734,6 +3734,11 @@ cifs_send_async_read(loff_t offset, size_t len, stru= ct cifsFileInfo *open_file, break; } =20 + if (cifs_sb->ctx->rsize =3D=3D 0) + cifs_sb->ctx->rsize =3D + server->ops->negotiate_rsize(tlink_tcon(open_file->tlink), + cifs_sb->ctx); + rc =3D server->ops->wait_mtu_credits(server, cifs_sb->ctx->rsize, &rsize, credits); if (rc) @@ -4512,6 +4517,11 @@ static int cifs_readpages(struct file *file, struct = address_space *mapping, break; } =20 + if (cifs_sb->ctx->rsize =3D=3D 0) + cifs_sb->ctx->rsize =3D + server->ops->negotiate_rsize(tlink_tcon(open_file->tlink), + cifs_sb->ctx); + rc =3D server->ops->wait_mtu_credits(server, cifs_sb->ctx->rsize, &rsize, credits); if (rc) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index c5b1dea54ebc..d8ca38ea8e22 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1631,6 +1631,7 @@ smb2_ioctl_query_info(const unsigned int xid, unsigned int size[2]; void *data[2]; int create_options =3D is_dir ? CREATE_NOT_FILE : CREATE_NOT_DIR; + void (*free_req1_func)(struct smb_rqst *r); =20 vars =3D kzalloc(sizeof(*vars), GFP_ATOMIC); if (vars =3D=3D NULL) @@ -1640,27 +1641,29 @@ smb2_ioctl_query_info(const unsigned int xid, =20 resp_buftype[0] =3D resp_buftype[1] =3D resp_buftype[2] =3D CIFS_NO_BUFFE= R; =20 - if (copy_from_user(&qi, arg, sizeof(struct smb_query_info))) - goto e_fault; - + if (copy_from_user(&qi, arg, sizeof(struct smb_query_info))) { + rc =3D -EFAULT; + goto free_vars; + } if (qi.output_buffer_length > 1024) { - kfree(vars); - return -EINVAL; + rc =3D -EINVAL; + goto free_vars; } =20 if (!ses || !server) { - kfree(vars); - return -EIO; + rc =3D -EIO; + goto free_vars; } =20 if (smb3_encryption_required(tcon)) flags |=3D CIFS_TRANSFORM_REQ; =20 - buffer =3D memdup_user(arg + sizeof(struct smb_query_info), - qi.output_buffer_length); - if (IS_ERR(buffer)) { - kfree(vars); - return PTR_ERR(buffer); + if (qi.output_buffer_length) { + buffer =3D memdup_user(arg + sizeof(struct smb_query_info), qi.output_bu= ffer_length); + if (IS_ERR(buffer)) { + rc =3D PTR_ERR(buffer); + goto free_vars; + } } =20 /* Open */ @@ -1698,45 +1701,45 @@ smb2_ioctl_query_info(const unsigned int xid, rc =3D SMB2_open_init(tcon, server, &rqst[0], &oplock, &oparms, path); if (rc) - goto iqinf_exit; + goto free_output_buffer; smb2_set_next_command(tcon, &rqst[0]); =20 /* Query */ if (qi.flags & PASSTHRU_FSCTL) { /* Can eventually relax perm check since server enforces too */ - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN)) { rc =3D -EPERM; - else { - rqst[1].rq_iov =3D &vars->io_iov[0]; - rqst[1].rq_nvec =3D SMB2_IOCTL_IOV_SIZE; - - rc =3D SMB2_ioctl_init(tcon, server, - &rqst[1], - COMPOUND_FID, COMPOUND_FID, - qi.info_type, true, buffer, - qi.output_buffer_length, - CIFSMaxBufSize - - MAX_SMB2_CREATE_RESPONSE_SIZE - - MAX_SMB2_CLOSE_RESPONSE_SIZE); + goto free_open_req; } + rqst[1].rq_iov =3D &vars->io_iov[0]; + rqst[1].rq_nvec =3D SMB2_IOCTL_IOV_SIZE; + + rc =3D SMB2_ioctl_init(tcon, server, &rqst[1], COMPOUND_FID, COMPOUND_FI= D, + qi.info_type, true, buffer, qi.output_buffer_length, + CIFSMaxBufSize - MAX_SMB2_CREATE_RESPONSE_SIZE - + MAX_SMB2_CLOSE_RESPONSE_SIZE); + free_req1_func =3D SMB2_ioctl_free; } else if (qi.flags =3D=3D PASSTHRU_SET_INFO) { /* Can eventually relax perm check since server enforces too */ - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN)) { rc =3D -EPERM; - else { - rqst[1].rq_iov =3D &vars->si_iov[0]; - rqst[1].rq_nvec =3D 1; - - size[0] =3D 8; - data[0] =3D buffer; - - rc =3D SMB2_set_info_init(tcon, server, - &rqst[1], - COMPOUND_FID, COMPOUND_FID, - current->tgid, - FILE_END_OF_FILE_INFORMATION, - SMB2_O_INFO_FILE, 0, data, size); + goto free_open_req; } + if (qi.output_buffer_length < 8) { + rc =3D -EINVAL; + goto free_open_req; + } + rqst[1].rq_iov =3D &vars->si_iov[0]; + rqst[1].rq_nvec =3D 1; + + /* MS-FSCC 2.4.13 FileEndOfFileInformation */ + size[0] =3D 8; + data[0] =3D buffer; + + rc =3D SMB2_set_info_init(tcon, server, &rqst[1], COMPOUND_FID, COMPOUND= _FID, + current->tgid, FILE_END_OF_FILE_INFORMATION, + SMB2_O_INFO_FILE, 0, data, size); + free_req1_func =3D SMB2_set_info_free; } else if (qi.flags =3D=3D PASSTHRU_QUERY_INFO) { rqst[1].rq_iov =3D &vars->qi_iov[0]; rqst[1].rq_nvec =3D 1; @@ -1747,6 +1750,7 @@ smb2_ioctl_query_info(const unsigned int xid, qi.info_type, qi.additional_information, qi.input_buffer_length, qi.output_buffer_length, buffer); + free_req1_func =3D SMB2_query_info_free; } else { /* unknown flags */ cifs_tcon_dbg(VFS, "Invalid passthru query flags: 0x%x\n", qi.flags); @@ -1754,7 +1758,7 @@ smb2_ioctl_query_info(const unsigned int xid, } =20 if (rc) - goto iqinf_exit; + goto free_open_req; smb2_set_next_command(tcon, &rqst[1]); smb2_set_related(&rqst[1]); =20 @@ -1765,14 +1769,14 @@ smb2_ioctl_query_info(const unsigned int xid, rc =3D SMB2_close_init(tcon, server, &rqst[2], COMPOUND_FID, COMPOUND_FID, false); if (rc) - goto iqinf_exit; + goto free_req_1; smb2_set_related(&rqst[2]); =20 rc =3D compound_send_recv(xid, ses, server, flags, 3, rqst, resp_buftype, rsp_iov); if (rc) - goto iqinf_exit; + goto out; =20 /* No need to bump num_remote_opens since handle immediately closed */ if (qi.flags & PASSTHRU_FSCTL) { @@ -1782,18 +1786,22 @@ smb2_ioctl_query_info(const unsigned int xid, qi.input_buffer_length =3D le32_to_cpu(io_rsp->OutputCount); if (qi.input_buffer_length > 0 && le32_to_cpu(io_rsp->OutputOffset) + qi.input_buffer_length - > rsp_iov[1].iov_len) - goto e_fault; + > rsp_iov[1].iov_len) { + rc =3D -EFAULT; + goto out; + } =20 if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length, - sizeof(qi.input_buffer_length))) - goto e_fault; + sizeof(qi.input_buffer_length))) { + rc =3D -EFAULT; + goto out; + } =20 if (copy_to_user((void __user *)pqi + sizeof(struct smb_query_info), (const void *)io_rsp + le32_to_cpu(io_rsp->OutputOffset), qi.input_buffer_length)) - goto e_fault; + rc =3D -EFAULT; } else { pqi =3D (struct smb_query_info __user *)arg; qi_rsp =3D (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; @@ -1801,28 +1809,30 @@ smb2_ioctl_query_info(const unsigned int xid, qi.input_buffer_length =3D le32_to_cpu(qi_rsp->OutputBufferLength); if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length, - sizeof(qi.input_buffer_length))) - goto e_fault; + sizeof(qi.input_buffer_length))) { + rc =3D -EFAULT; + goto out; + } =20 if (copy_to_user(pqi + 1, qi_rsp->Buffer, qi.input_buffer_length)) - goto e_fault; + rc =3D -EFAULT; } =20 - iqinf_exit: - cifs_small_buf_release(rqst[0].rq_iov[0].iov_base); - cifs_small_buf_release(rqst[1].rq_iov[0].iov_base); - cifs_small_buf_release(rqst[2].rq_iov[0].iov_base); +out: free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); - kfree(vars); + SMB2_close_free(&rqst[2]); +free_req_1: + free_req1_func(&rqst[1]); +free_open_req: + SMB2_open_free(&rqst[0]); +free_output_buffer: kfree(buffer); +free_vars: + kfree(vars); return rc; - -e_fault: - rc =3D -EFAULT; - goto iqinf_exit; } =20 static ssize_t diff --git a/fs/coredump.c b/fs/coredump.c index a6b3c196cdef..f5e22e3e3016 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -41,6 +41,7 @@ #include #include #include +#include =20 #include #include @@ -52,6 +53,9 @@ =20 #include =20 +static bool dump_vma_snapshot(struct coredump_params *cprm); +static void free_vma_snapshot(struct coredump_params *cprm); + int core_uses_pid; unsigned int core_pipe_limit; char core_pattern[CORENAME_MAX_SIZE] =3D "core"; @@ -534,6 +538,7 @@ void do_coredump(const kernel_siginfo_t *siginfo) * by any locks. */ .mm_flags =3D mm->flags, + .vma_meta =3D NULL, }; =20 audit_core_dumps(siginfo->si_signo); @@ -748,6 +753,9 @@ void do_coredump(const kernel_siginfo_t *siginfo) pr_info("Core dump to |%s disabled\n", cn.corename); goto close_fail; } + if (!dump_vma_snapshot(&cprm)) + goto close_fail; + file_start_write(cprm.file); core_dumped =3D binfmt->core_dump(&cprm); /* @@ -761,6 +769,7 @@ void do_coredump(const kernel_siginfo_t *siginfo) dump_emit(&cprm, "", 1); } file_end_write(cprm.file); + free_vma_snapshot(&cprm); } if (ispipe && core_pipe_limit) wait_for_dump_helpers(cprm.file); @@ -926,6 +935,8 @@ static bool always_dump_vma(struct vm_area_struct *vma) return false; } =20 +#define DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER 1 + /* * Decide how much of @vma's contents should be included in a core dump. */ @@ -985,9 +996,20 @@ static unsigned long vma_dump_size(struct vm_area_stru= ct *vma, * dump the first page to aid in determining what was mapped here. */ if (FILTER(ELF_HEADERS) && - vma->vm_pgoff =3D=3D 0 && (vma->vm_flags & VM_READ) && - (READ_ONCE(file_inode(vma->vm_file)->i_mode) & 0111) !=3D 0) - return PAGE_SIZE; + vma->vm_pgoff =3D=3D 0 && (vma->vm_flags & VM_READ)) { + if ((READ_ONCE(file_inode(vma->vm_file)->i_mode) & 0111) !=3D 0) + return PAGE_SIZE; + + /* + * ELF libraries aren't always executable. + * We'll want to check whether the mapping starts with the ELF + * magic, but not now - we're holding the mmap lock, + * so copy_from_user() doesn't work here. + * Use a placeholder instead, and fix it up later in + * dump_vma_snapshot(). + */ + return DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER; + } =20 #undef FILTER =20 @@ -1024,18 +1046,29 @@ static struct vm_area_struct *next_vma(struct vm_ar= ea_struct *this_vma, return gate_vma; } =20 +static void free_vma_snapshot(struct coredump_params *cprm) +{ + if (cprm->vma_meta) { + int i; + for (i =3D 0; i < cprm->vma_count; i++) { + struct file *file =3D cprm->vma_meta[i].file; + if (file) + fput(file); + } + kvfree(cprm->vma_meta); + cprm->vma_meta =3D NULL; + } +} + /* * Under the mmap_lock, take a snapshot of relevant information about the = task's * VMAs. */ -int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count, - struct core_vma_metadata **vma_meta, - size_t *vma_data_size_ptr) +static bool dump_vma_snapshot(struct coredump_params *cprm) { struct vm_area_struct *vma, *gate_vma; struct mm_struct *mm =3D current->mm; int i; - size_t vma_data_size =3D 0; =20 /* * Once the stack expansion code is fixed to not change VMA bounds @@ -1043,36 +1076,51 @@ int dump_vma_snapshot(struct coredump_params *cprm,= int *vma_count, * mmap_lock in read mode. */ if (mmap_write_lock_killable(mm)) - return -EINTR; + return false; =20 + cprm->vma_data_size =3D 0; gate_vma =3D get_gate_vma(mm); - *vma_count =3D mm->map_count + (gate_vma ? 1 : 0); + cprm->vma_count =3D mm->map_count + (gate_vma ? 1 : 0); =20 - *vma_meta =3D kvmalloc_array(*vma_count, sizeof(**vma_meta), GFP_KERNEL); - if (!*vma_meta) { + cprm->vma_meta =3D kvmalloc_array(cprm->vma_count, sizeof(*cprm->vma_meta= ), GFP_KERNEL); + if (!cprm->vma_meta) { mmap_write_unlock(mm); - return -ENOMEM; + return false; } =20 for (i =3D 0, vma =3D first_vma(current, gate_vma); vma !=3D NULL; vma =3D next_vma(vma, gate_vma), i++) { - struct core_vma_metadata *m =3D (*vma_meta) + i; + struct core_vma_metadata *m =3D cprm->vma_meta + i; =20 m->start =3D vma->vm_start; m->end =3D vma->vm_end; m->flags =3D vma->vm_flags; m->dump_size =3D vma_dump_size(vma, cprm->mm_flags); + m->pgoff =3D vma->vm_pgoff; =20 - vma_data_size +=3D m->dump_size; + m->file =3D vma->vm_file; + if (m->file) + get_file(m->file); } =20 mmap_write_unlock(mm); =20 - if (WARN_ON(i !=3D *vma_count)) { - kvfree(*vma_meta); - return -EFAULT; + for (i =3D 0; i < cprm->vma_count; i++) { + struct core_vma_metadata *m =3D cprm->vma_meta + i; + + if (m->dump_size =3D=3D DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER) { + char elfmag[SELFMAG]; + + if (copy_from_user(elfmag, (void __user *)m->start, SELFMAG) || + memcmp(elfmag, ELFMAG, SELFMAG) !=3D 0) { + m->dump_size =3D 0; + } else { + m->dump_size =3D PAGE_SIZE; + } + } + + cprm->vma_data_size +=3D m->dump_size; } =20 - *vma_data_size_ptr =3D vma_data_size; - return 0; + return true; } diff --git a/fs/exec.c b/fs/exec.c index 537d92c41105..690aaab256fd 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -494,8 +494,14 @@ static int bprm_stack_limits(struct linux_binprm *bprm) * the stack. They aren't stored until much later when we can't * signal to the parent that the child has run out of stack space. * Instead, calculate it here so it's possible to fail gracefully. + * + * In the case of argc =3D 0, make sure there is space for adding a + * empty string (which will bump argc to 1), to ensure confused + * userspace programs don't start processing from argv[1], thinking + * argc can never be 0, to keep them from walking envp by accident. + * See do_execveat_common(). */ - ptr_size =3D (bprm->argc + bprm->envc) * sizeof(void *); + ptr_size =3D (max(bprm->argc, 1) + bprm->envc) * sizeof(void *); if (limit <=3D ptr_size) return -E2BIG; limit -=3D ptr_size; @@ -1893,6 +1899,9 @@ static int do_execveat_common(int fd, struct filename= *filename, } =20 retval =3D count(argv, MAX_ARG_STRINGS); + if (retval =3D=3D 0) + pr_warn_once("process '%s' launched '%s' with NULL argv: empty string ad= ded\n", + current->comm, bprm->filename); if (retval < 0) goto out_free; bprm->argc =3D retval; @@ -1919,6 +1928,19 @@ static int do_execveat_common(int fd, struct filenam= e *filename, if (retval < 0) goto out_free; =20 + /* + * When argv is empty, add an empty string ("") as argv[0] to + * ensure confused userspace programs that start processing + * from argv[1] won't end up walking envp. See also + * bprm_stack_limits(). + */ + if (bprm->argc =3D=3D 0) { + retval =3D copy_string_kernel("", bprm); + if (retval < 0) + goto out_free; + bprm->argc =3D 1; + } + retval =3D bprm_execve(bprm, fd, filename, flags); out_free: free_bprm(bprm); @@ -1947,6 +1969,8 @@ int kernel_execve(const char *kernel_filename, } =20 retval =3D count_strings_kernel(argv); + if (WARN_ON_ONCE(retval =3D=3D 0)) + retval =3D -EINVAL; if (retval < 0) goto out_free; bprm->argc =3D retval; diff --git a/fs/ext2/super.c b/fs/ext2/super.c index d8d580b609ba..3d21279fe2cb 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -753,8 +753,12 @@ static loff_t ext2_max_size(int bits) res +=3D 1LL << (bits-2); res +=3D 1LL << (2*(bits-2)); res +=3D 1LL << (3*(bits-2)); + /* Compute how many metadata blocks are needed */ + meta_blocks =3D 1; + meta_blocks +=3D 1 + ppb; + meta_blocks +=3D 1 + ppb + ppb * ppb; /* Does block tree limit file size? */ - if (res < upper_limit) + if (res + meta_blocks <=3D upper_limit) goto check_lfs; =20 res =3D upper_limit; diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index d091133a4b46..46fdb40c3962 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -1788,19 +1788,20 @@ bool empty_inline_dir(struct inode *dir, int *has_i= nline_data) void *inline_pos; unsigned int offset; struct ext4_dir_entry_2 *de; - bool ret =3D true; + bool ret =3D false; =20 err =3D ext4_get_inode_loc(dir, &iloc); if (err) { EXT4_ERROR_INODE_ERR(dir, -err, "error %d getting inode %lu block", err, dir->i_ino); - return true; + return false; } =20 down_read(&EXT4_I(dir)->xattr_sem); if (!ext4_has_inline_data(dir)) { *has_inline_data =3D 0; + ret =3D true; goto out; } =20 @@ -1809,7 +1810,6 @@ bool empty_inline_dir(struct inode *dir, int *has_inl= ine_data) ext4_warning(dir->i_sb, "bad inline directory (dir #%lu) - no `..'", dir->i_ino); - ret =3D true; goto out; } =20 @@ -1828,16 +1828,15 @@ bool empty_inline_dir(struct inode *dir, int *has_i= nline_data) dir->i_ino, le32_to_cpu(de->inode), le16_to_cpu(de->rec_len), de->name_len, inline_size); - ret =3D true; goto out; } if (le32_to_cpu(de->inode)) { - ret =3D false; goto out; } offset +=3D ext4_rec_len_from_disk(de->rec_len, inline_size); } =20 + ret =3D true; out: up_read(&EXT4_I(dir)->xattr_sem); brelse(iloc.bh); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 2f5686dfa30d..a61d1e4e1026 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1992,6 +1992,15 @@ static int ext4_writepage(struct page *page, else len =3D PAGE_SIZE; =20 + /* Should never happen but for bugs in other kernel subsystems */ + if (!page_has_buffers(page)) { + ext4_warning_inode(inode, + "page %lu does not have buffers attached", page->index); + ClearPageDirty(page); + unlock_page(page); + return 0; + } + page_bufs =3D page_buffers(page); /* * We cannot do block allocation or other extent handling in this @@ -2595,6 +2604,22 @@ static int mpage_prepare_extent_to_map(struct mpage_= da_data *mpd) wait_on_page_writeback(page); BUG_ON(PageWriteback(page)); =20 + /* + * Should never happen but for buggy code in + * other subsystems that call + * set_page_dirty() without properly warning + * the file system first. See [1] for more + * information. + * + * [1] https://lore.kernel.org/linux-mm/20180103100430.GE4911@quack2.su= se.cz + */ + if (!page_has_buffers(page)) { + ext4_warning_inode(mpd->inode, "page %lu does not have buffers attache= d", page->index); + ClearPageDirty(page); + unlock_page(page); + continue; + } + if (mpd->map.m_len =3D=3D 0) mpd->first_page =3D page->index; mpd->next_page =3D page->index + 1; diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index c849fd845d9b..b53c07c5c760 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -1000,7 +1000,7 @@ static inline int should_optimize_scan(struct ext4_al= location_context *ac) return 0; if (ac->ac_criteria >=3D 2) return 0; - if (ext4_test_inode_flag(ac->ac_inode, EXT4_INODE_EXTENTS)) + if (!ext4_test_inode_flag(ac->ac_inode, EXT4_INODE_EXTENTS)) return 0; return 1; } @@ -3899,69 +3899,95 @@ void ext4_mb_mark_bb(struct super_block *sb, ext4_f= sblk_t block, struct ext4_sb_info *sbi =3D EXT4_SB(sb); ext4_group_t group; ext4_grpblk_t blkoff; - int i, clen, err; + int i, err; int already; + unsigned int clen, clen_changed, thisgrp_len; =20 - clen =3D EXT4_B2C(sbi, len); + while (len > 0) { + ext4_get_group_no_and_offset(sb, block, &group, &blkoff); =20 - ext4_get_group_no_and_offset(sb, block, &group, &blkoff); - bitmap_bh =3D ext4_read_block_bitmap(sb, group); - if (IS_ERR(bitmap_bh)) { - err =3D PTR_ERR(bitmap_bh); - bitmap_bh =3D NULL; - goto out_err; - } + /* + * Check to see if we are freeing blocks across a group + * boundary. + * In case of flex_bg, this can happen that (block, len) may + * span across more than one group. In that case we need to + * get the corresponding group metadata to work with. + * For this we have goto again loop. + */ + thisgrp_len =3D min_t(unsigned int, (unsigned int)len, + EXT4_BLOCKS_PER_GROUP(sb) - EXT4_C2B(sbi, blkoff)); + clen =3D EXT4_NUM_B2C(sbi, thisgrp_len); =20 - err =3D -EIO; - gdp =3D ext4_get_group_desc(sb, group, &gdp_bh); - if (!gdp) - goto out_err; + bitmap_bh =3D ext4_read_block_bitmap(sb, group); + if (IS_ERR(bitmap_bh)) { + err =3D PTR_ERR(bitmap_bh); + bitmap_bh =3D NULL; + break; + } =20 - ext4_lock_group(sb, group); - already =3D 0; - for (i =3D 0; i < clen; i++) - if (!mb_test_bit(blkoff + i, bitmap_bh->b_data) =3D=3D !state) - already++; + err =3D -EIO; + gdp =3D ext4_get_group_desc(sb, group, &gdp_bh); + if (!gdp) + break; =20 - if (state) - ext4_set_bits(bitmap_bh->b_data, blkoff, clen); - else - mb_test_and_clear_bits(bitmap_bh->b_data, blkoff, clen); - if (ext4_has_group_desc_csum(sb) && - (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) { - gdp->bg_flags &=3D cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); - ext4_free_group_clusters_set(sb, gdp, - ext4_free_clusters_after_init(sb, - group, gdp)); - } - if (state) - clen =3D ext4_free_group_clusters(sb, gdp) - clen + already; - else - clen =3D ext4_free_group_clusters(sb, gdp) + clen - already; + ext4_lock_group(sb, group); + already =3D 0; + for (i =3D 0; i < clen; i++) + if (!mb_test_bit(blkoff + i, bitmap_bh->b_data) =3D=3D + !state) + already++; + + clen_changed =3D clen - already; + if (state) + ext4_set_bits(bitmap_bh->b_data, blkoff, clen); + else + mb_test_and_clear_bits(bitmap_bh->b_data, blkoff, clen); + if (ext4_has_group_desc_csum(sb) && + (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) { + gdp->bg_flags &=3D cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); + ext4_free_group_clusters_set(sb, gdp, + ext4_free_clusters_after_init(sb, group, gdp)); + } + if (state) + clen =3D ext4_free_group_clusters(sb, gdp) - clen_changed; + else + clen =3D ext4_free_group_clusters(sb, gdp) + clen_changed; =20 - ext4_free_group_clusters_set(sb, gdp, clen); - ext4_block_bitmap_csum_set(sb, group, gdp, bitmap_bh); - ext4_group_desc_csum_set(sb, group, gdp); + ext4_free_group_clusters_set(sb, gdp, clen); + ext4_block_bitmap_csum_set(sb, group, gdp, bitmap_bh); + ext4_group_desc_csum_set(sb, group, gdp); =20 - ext4_unlock_group(sb, group); + ext4_unlock_group(sb, group); =20 - if (sbi->s_log_groups_per_flex) { - ext4_group_t flex_group =3D ext4_flex_group(sbi, group); + if (sbi->s_log_groups_per_flex) { + ext4_group_t flex_group =3D ext4_flex_group(sbi, group); + struct flex_groups *fg =3D sbi_array_rcu_deref(sbi, + s_flex_groups, flex_group); =20 - atomic64_sub(len, - &sbi_array_rcu_deref(sbi, s_flex_groups, - flex_group)->free_clusters); + if (state) + atomic64_sub(clen_changed, &fg->free_clusters); + else + atomic64_add(clen_changed, &fg->free_clusters); + + } + + err =3D ext4_handle_dirty_metadata(NULL, NULL, bitmap_bh); + if (err) + break; + sync_dirty_buffer(bitmap_bh); + err =3D ext4_handle_dirty_metadata(NULL, NULL, gdp_bh); + sync_dirty_buffer(gdp_bh); + if (err) + break; + + block +=3D thisgrp_len; + len -=3D thisgrp_len; + brelse(bitmap_bh); + BUG_ON(len < 0); } =20 - err =3D ext4_handle_dirty_metadata(NULL, NULL, bitmap_bh); if (err) - goto out_err; - sync_dirty_buffer(bitmap_bh); - err =3D ext4_handle_dirty_metadata(NULL, NULL, gdp_bh); - sync_dirty_buffer(gdp_bh); - -out_err: - brelse(bitmap_bh); + brelse(bitmap_bh); } =20 /* diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 47b9f87dbc6f..94db928d1c9e 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2997,14 +2997,14 @@ bool ext4_empty_dir(struct inode *inode) if (inode->i_size < ext4_dir_rec_len(1, NULL) + ext4_dir_rec_len(2, NULL)) { EXT4_ERROR_INODE(inode, "invalid size"); - return true; + return false; } /* The first directory block must not be a hole, * so treat it as DIRENT_HTREE */ bh =3D ext4_read_dirblock(inode, 0, DIRENT_HTREE); if (IS_ERR(bh)) - return true; + return false; =20 de =3D (struct ext4_dir_entry_2 *) bh->b_data; if (ext4_check_dir_entry(inode, NULL, de, bh, bh->b_data, bh->b_size, @@ -3012,7 +3012,7 @@ bool ext4_empty_dir(struct inode *inode) le32_to_cpu(de->inode) !=3D inode->i_ino || strcmp(".", de->name)) { ext4_warning_inode(inode, "directory missing '.'"); brelse(bh); - return true; + return false; } offset =3D ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize); de =3D ext4_next_entry(de, sb->s_blocksize); @@ -3021,7 +3021,7 @@ bool ext4_empty_dir(struct inode *inode) le32_to_cpu(de->inode) =3D=3D 0 || strcmp("..", de->name)) { ext4_warning_inode(inode, "directory missing '..'"); brelse(bh); - return true; + return false; } offset +=3D ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize); while (offset < inode->i_size) { @@ -3035,7 +3035,7 @@ bool ext4_empty_dir(struct inode *inode) continue; } if (IS_ERR(bh)) - return true; + return false; } de =3D (struct ext4_dir_entry_2 *) (bh->b_data + (offset & (sb->s_blocksize - 1))); diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 2011e9742443..d913cd9fecea 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -864,6 +864,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_= info *sbi, struct page *cp_page_1 =3D NULL, *cp_page_2 =3D NULL; struct f2fs_checkpoint *cp_block =3D NULL; unsigned long long cur_version =3D 0, pre_version =3D 0; + unsigned int cp_blocks; int err; =20 err =3D get_checkpoint_version(sbi, cp_addr, &cp_block, @@ -871,15 +872,16 @@ static struct page *validate_checkpoint(struct f2fs_s= b_info *sbi, if (err) return NULL; =20 - if (le32_to_cpu(cp_block->cp_pack_total_block_count) > - sbi->blocks_per_seg) { + cp_blocks =3D le32_to_cpu(cp_block->cp_pack_total_block_count); + + if (cp_blocks > sbi->blocks_per_seg || cp_blocks <=3D F2FS_CP_PACKS) { f2fs_warn(sbi, "invalid cp_pack_total_block_count:%u", le32_to_cpu(cp_block->cp_pack_total_block_count)); goto invalid_cp; } pre_version =3D *version; =20 - cp_addr +=3D le32_to_cpu(cp_block->cp_pack_total_block_count) - 1; + cp_addr +=3D cp_blocks - 1; err =3D get_checkpoint_version(sbi, cp_addr, &cp_block, &cp_page_2, version); if (err) diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c index 190a3c4d4c91..ced0fd54658c 100644 --- a/fs/f2fs/compress.c +++ b/fs/f2fs/compress.c @@ -313,10 +313,9 @@ static int lz4_decompress_pages(struct decompress_io_c= tx *dic) } =20 if (ret !=3D PAGE_SIZE << dic->log_cluster_size) { - printk_ratelimited("%sF2FS-fs (%s): lz4 invalid rlen:%zu, " + printk_ratelimited("%sF2FS-fs (%s): lz4 invalid ret:%d, " "expected:%lu\n", KERN_ERR, - F2FS_I_SB(dic->inode)->sb->s_id, - dic->rlen, + F2FS_I_SB(dic->inode)->sb->s_id, ret, PAGE_SIZE << dic->log_cluster_size); return -EIO; } diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 3ba75587a2cd..5b4b26130844 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -3267,8 +3267,12 @@ static int __f2fs_write_data_pages(struct address_sp= ace *mapping, /* to avoid spliting IOs due to mixed WB_SYNC_ALL and WB_SYNC_NONE */ if (wbc->sync_mode =3D=3D WB_SYNC_ALL) atomic_inc(&sbi->wb_sync_req[DATA]); - else if (atomic_read(&sbi->wb_sync_req[DATA])) + else if (atomic_read(&sbi->wb_sync_req[DATA])) { + /* to avoid potential deadlock */ + if (current->plug) + blk_finish_plug(current->plug); goto skip_write; + } =20 if (__should_serialize_io(inode, wbc)) { mutex_lock(&sbi->writepages); @@ -3459,7 +3463,7 @@ static int f2fs_write_begin(struct file *file, struct= address_space *mapping, =20 *fsdata =3D NULL; =20 - if (len =3D=3D PAGE_SIZE) + if (len =3D=3D PAGE_SIZE && !(f2fs_is_atomic_file(inode))) goto repeat; =20 ret =3D f2fs_prepare_compress_overwrite(inode, pagep, diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index 8c50518475a9..b449c7a372a4 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -21,7 +21,7 @@ #include "gc.h" =20 static LIST_HEAD(f2fs_stat_list); -static DEFINE_MUTEX(f2fs_stat_mutex); +static DEFINE_RAW_SPINLOCK(f2fs_stat_lock); #ifdef CONFIG_DEBUG_FS static struct dentry *f2fs_debugfs_root; #endif @@ -338,14 +338,16 @@ static char *s_flag[] =3D { [SBI_QUOTA_SKIP_FLUSH] =3D " quota_skip_flush", [SBI_QUOTA_NEED_REPAIR] =3D " quota_need_repair", [SBI_IS_RESIZEFS] =3D " resizefs", + [SBI_IS_FREEZING] =3D " freezefs", }; =20 static int stat_show(struct seq_file *s, void *v) { struct f2fs_stat_info *si; int i =3D 0, j =3D 0; + unsigned long flags; =20 - mutex_lock(&f2fs_stat_mutex); + raw_spin_lock_irqsave(&f2fs_stat_lock, flags); list_for_each_entry(si, &f2fs_stat_list, stat_list) { update_general_status(si->sbi); =20 @@ -573,7 +575,7 @@ static int stat_show(struct seq_file *s, void *v) seq_printf(s, " - paged : %llu KB\n", si->page_mem >> 10); } - mutex_unlock(&f2fs_stat_mutex); + raw_spin_unlock_irqrestore(&f2fs_stat_lock, flags); return 0; } =20 @@ -584,6 +586,7 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) { struct f2fs_super_block *raw_super =3D F2FS_RAW_SUPER(sbi); struct f2fs_stat_info *si; + unsigned long flags; int i; =20 si =3D f2fs_kzalloc(sbi, sizeof(struct f2fs_stat_info), GFP_KERNEL); @@ -619,9 +622,9 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) atomic_set(&sbi->max_aw_cnt, 0); atomic_set(&sbi->max_vw_cnt, 0); =20 - mutex_lock(&f2fs_stat_mutex); + raw_spin_lock_irqsave(&f2fs_stat_lock, flags); list_add_tail(&si->stat_list, &f2fs_stat_list); - mutex_unlock(&f2fs_stat_mutex); + raw_spin_unlock_irqrestore(&f2fs_stat_lock, flags); =20 return 0; } @@ -629,10 +632,11 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) void f2fs_destroy_stats(struct f2fs_sb_info *sbi) { struct f2fs_stat_info *si =3D F2FS_STAT(sbi); + unsigned long flags; =20 - mutex_lock(&f2fs_stat_mutex); + raw_spin_lock_irqsave(&f2fs_stat_lock, flags); list_del(&si->stat_list); - mutex_unlock(&f2fs_stat_mutex); + raw_spin_unlock_irqrestore(&f2fs_stat_lock, flags); =20 kfree(si); } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index d753094a4919..980c0c2b6350 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1259,6 +1259,7 @@ enum { SBI_QUOTA_SKIP_FLUSH, /* skip flushing quota in current CP */ SBI_QUOTA_NEED_REPAIR, /* quota file may be corrupted */ SBI_IS_RESIZEFS, /* resizefs is in process */ + SBI_IS_FREEZING, /* freezefs is in process */ }; =20 enum { diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index b752d1a6e6ff..21dde125ff77 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -2002,7 +2002,10 @@ static int f2fs_ioc_start_atomic_write(struct file *= filp) =20 inode_lock(inode); =20 - f2fs_disable_compressed_file(inode); + if (!f2fs_disable_compressed_file(inode)) { + ret =3D -EINVAL; + goto out; + } =20 if (f2fs_is_atomic_file(inode)) { if (is_inode_flag_set(inode, FI_ATOMIC_REVOKE_REQUEST)) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index b538cbcba351..fc9e33859b6c 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -1026,8 +1026,10 @@ static bool is_alive(struct f2fs_sb_info *sbi, struc= t f2fs_summary *sum, set_sbi_flag(sbi, SBI_NEED_FSCK); } =20 - if (f2fs_check_nid_range(sbi, dni->ino)) + if (f2fs_check_nid_range(sbi, dni->ino)) { + f2fs_put_page(node_page, 1); return false; + } =20 *nofs =3D ofs_of_node(node_page); source_blkaddr =3D data_blkaddr(NULL, node_page, ofs_in_node); diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 1db7823d5a13..a40e52ba5ec8 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -769,7 +769,8 @@ void f2fs_evict_inode(struct inode *inode) f2fs_remove_ino_entry(sbi, inode->i_ino, UPDATE_INO); f2fs_remove_ino_entry(sbi, inode->i_ino, FLUSH_INO); =20 - sb_start_intwrite(inode->i_sb); + if (!is_sbi_flag_set(sbi, SBI_IS_FREEZING)) + sb_start_intwrite(inode->i_sb); set_inode_flag(inode, FI_NO_ALLOC); i_size_write(inode, 0); retry: @@ -800,7 +801,8 @@ void f2fs_evict_inode(struct inode *inode) if (dquot_initialize_needed(inode)) set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); } - sb_end_intwrite(inode->i_sb); + if (!is_sbi_flag_set(sbi, SBI_IS_FREEZING)) + sb_end_intwrite(inode->i_sb); no_delete: dquot_drop(inode); =20 @@ -876,6 +878,7 @@ void f2fs_handle_failed_inode(struct inode *inode) err =3D f2fs_get_node_info(sbi, inode->i_ino, &ni); if (err) { set_sbi_flag(sbi, SBI_NEED_FSCK); + set_inode_flag(inode, FI_FREE_NID); f2fs_warn(sbi, "May loss orphan inode, run fsck to fix."); goto out; } diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 556fcd8457f3..69c6bcaf5aae 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -2106,8 +2106,12 @@ static int f2fs_write_node_pages(struct address_spac= e *mapping, =20 if (wbc->sync_mode =3D=3D WB_SYNC_ALL) atomic_inc(&sbi->wb_sync_req[NODE]); - else if (atomic_read(&sbi->wb_sync_req[NODE])) + else if (atomic_read(&sbi->wb_sync_req[NODE])) { + /* to avoid potential deadlock */ + if (current->plug) + blk_finish_plug(current->plug); goto skip_write; + } =20 trace_f2fs_writepages(mapping->host, wbc, NODE); =20 diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index df9ed75f0b7a..5fd33aabd0fc 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -4792,6 +4792,13 @@ static int sanity_check_curseg(struct f2fs_sb_info *= sbi) =20 sanity_check_seg_type(sbi, curseg->seg_type); =20 + if (curseg->alloc_type !=3D LFS && curseg->alloc_type !=3D SSR) { + f2fs_err(sbi, + "Current segment has invalid alloc_type:%d", + curseg->alloc_type); + return -EFSCORRUPTED; + } + if (f2fs_test_bit(blkofs, se->cur_valid_map)) goto out; =20 diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 08faa787a773..9402d5b2c7fd 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1668,11 +1668,15 @@ static int f2fs_freeze(struct super_block *sb) /* ensure no checkpoint required */ if (!llist_empty(&F2FS_SB(sb)->cprc_info.issue_list)) return -EINVAL; + + /* to avoid deadlock on f2fs_evict_inode->SB_FREEZE_FS */ + set_sbi_flag(F2FS_SB(sb), SBI_IS_FREEZING); return 0; } =20 static int f2fs_unfreeze(struct super_block *sb) { + clear_sbi_flag(F2FS_SB(sb), SBI_IS_FREEZING); return 0; } =20 @@ -2695,7 +2699,7 @@ int f2fs_quota_sync(struct super_block *sb, int type) struct f2fs_sb_info *sbi =3D F2FS_SB(sb); struct quota_info *dqopt =3D sb_dqopt(sb); int cnt; - int ret; + int ret =3D 0; =20 /* * Now when everything is written we can discard the pagecache so @@ -2706,8 +2710,8 @@ int f2fs_quota_sync(struct super_block *sb, int type) if (type !=3D -1 && cnt !=3D type) continue; =20 - if (!sb_has_quota_active(sb, type)) - return 0; + if (!sb_has_quota_active(sb, cnt)) + continue; =20 inode_lock(dqopt->files[cnt]); =20 diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 8cdeac090f81..8885c7383472 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -473,7 +473,7 @@ static ssize_t __sbi_store(struct f2fs_attr *a, } else if (t =3D=3D GC_IDLE_AT) { if (!sbi->am.atgc_enabled) return -EINVAL; - sbi->gc_mode =3D GC_AT; + sbi->gc_mode =3D GC_IDLE_AT; } else { sbi->gc_mode =3D GC_NORMAL; } diff --git a/fs/file.c b/fs/file.c index 97d212a9b814..ee9317346702 100644 --- a/fs/file.c +++ b/fs/file.c @@ -87,6 +87,21 @@ static void copy_fdtable(struct fdtable *nfdt, struct fd= table *ofdt) copy_fd_bitmaps(nfdt, ofdt, ofdt->max_fds); } =20 +/* + * Note how the fdtable bitmap allocations very much have to be a multiple= of + * BITS_PER_LONG. This is not only because we walk those things in chunks = of + * 'unsigned long' in some places, but simply because that is how the Linux + * kernel bitmaps are defined to work: they are not "bits in an array of b= ytes", + * they are very much "bits in an array of unsigned long". + * + * The ALIGN(nr, BITS_PER_LONG) here is for clarity: since we just multipl= ied + * by that "1024/sizeof(ptr)" before, we already know there are sufficient + * clear low bits. Clang seems to realize that, gcc ends up being confused. + * + * On a 128-bit machine, the ALIGN() would actually matter. In the meantim= e, + * let's consider it documentation (and maybe a test-case for gcc to impro= ve + * its code generation ;) + */ static struct fdtable * alloc_fdtable(unsigned int nr) { struct fdtable *fdt; @@ -102,6 +117,7 @@ static struct fdtable * alloc_fdtable(unsigned int nr) nr /=3D (1024 / sizeof(struct file *)); nr =3D roundup_pow_of_two(nr + 1); nr *=3D (1024 / sizeof(struct file *)); + nr =3D ALIGN(nr, BITS_PER_LONG); /* * Note that this can drive nr *below* what we had passed if sysctl_nr_op= en * had been set lower between the check in expand_files() and here. Deal @@ -269,6 +285,19 @@ static unsigned int count_open_files(struct fdtable *f= dt) return i; } =20 +/* + * Note that a sane fdtable size always has to be a multiple of + * BITS_PER_LONG, since we have bitmaps that are sized by this. + * + * 'max_fds' will normally already be properly aligned, but it + * turns out that in the close_range() -> __close_range() -> + * unshare_fd() -> dup_fd() -> sane_fdtable_size() we can end + * up having a 'max_fds' value that isn't already aligned. + * + * Rather than make close_range() have to worry about this, + * just make that BITS_PER_LONG alignment be part of a sane + * fdtable size. Becuase that's really what it is. + */ static unsigned int sane_fdtable_size(struct fdtable *fdt, unsigned int ma= x_fds) { unsigned int count; @@ -276,7 +305,7 @@ static unsigned int sane_fdtable_size(struct fdtable *f= dt, unsigned int max_fds) count =3D count_open_files(fdt); if (max_fds < NR_OPEN_DEFAULT) max_fds =3D NR_OPEN_DEFAULT; - return min(count, max_fds); + return ALIGN(min(count, max_fds), BITS_PER_LONG); } =20 /* diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index d67108489148..fbdb7a30470a 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -2146,7 +2146,7 @@ int gfs2_setattr_size(struct inode *inode, u64 newsiz= e) =20 ret =3D do_shrink(inode, newsize); out: - gfs2_rs_delete(ip, NULL); + gfs2_rs_delete(ip); gfs2_qa_put(ip); return ret; } diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 8c39a8571b1f..b53ad18e5ccb 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -706,7 +706,7 @@ static int gfs2_release(struct inode *inode, struct fil= e *file) =20 if (file->f_mode & FMODE_WRITE) { if (gfs2_rs_active(&ip->i_res)) - gfs2_rs_delete(ip, &inode->i_writecount); + gfs2_rs_delete(ip); gfs2_qa_put(ip); } return 0; @@ -1083,6 +1083,7 @@ static ssize_t gfs2_file_buffered_write(struct kiocb = *iocb, gfs2_holder_uninit(gh); if (statfs_gh) kfree(statfs_gh); + from->count =3D orig_count - read; return read ? read : ret; } =20 diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 89905f4f29bb..66a123306aec 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -793,7 +793,7 @@ static int gfs2_create_inode(struct inode *dir, struct = dentry *dentry, if (free_vfs_inode) /* else evict will do the put for us */ gfs2_glock_put(ip->i_gl); } - gfs2_rs_delete(ip, NULL); + gfs2_rs_deltree(&ip->i_res); gfs2_qa_put(ip); fail_free_acls: posix_acl_release(default_acl); diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 0fb3c01bc557..3b34bb24d0af 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -680,13 +680,14 @@ void gfs2_rs_deltree(struct gfs2_blkreserv *rs) /** * gfs2_rs_delete - delete a multi-block reservation * @ip: The inode for this reservation - * @wcount: The inode's write count, or NULL * */ -void gfs2_rs_delete(struct gfs2_inode *ip, atomic_t *wcount) +void gfs2_rs_delete(struct gfs2_inode *ip) { + struct inode *inode =3D &ip->i_inode; + down_write(&ip->i_rw_mutex); - if ((wcount =3D=3D NULL) || (atomic_read(wcount) <=3D 1)) + if (atomic_read(&inode->i_writecount) <=3D 1) gfs2_rs_deltree(&ip->i_res); up_write(&ip->i_rw_mutex); } @@ -1415,7 +1416,8 @@ int gfs2_fitrim(struct file *filp, void __user *argp) =20 start =3D r.start >> bs_shift; end =3D start + (r.len >> bs_shift); - minlen =3D max_t(u64, r.minlen, + minlen =3D max_t(u64, r.minlen, sdp->sd_sb.sb_bsize); + minlen =3D max_t(u64, minlen, q->limits.discard_granularity) >> bs_shift; =20 if (end <=3D start || minlen > sdp->sd_max_rg_data) diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index 3e2ca1fb4305..46dd94e9e085 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -45,7 +45,7 @@ extern int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *= bn, unsigned int *n, bool dinode, u64 *generation); =20 extern void gfs2_rs_deltree(struct gfs2_blkreserv *rs); -extern void gfs2_rs_delete(struct gfs2_inode *ip, atomic_t *wcount); +extern void gfs2_rs_delete(struct gfs2_inode *ip); extern void __gfs2_free_blocks(struct gfs2_inode *ip, struct gfs2_rgrpd *r= gd, u64 bstart, u32 blen, int meta); extern void gfs2_free_meta(struct gfs2_inode *ip, struct gfs2_rgrpd *rgd, diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 0f93e8beca4d..313a8be610ef 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1398,7 +1398,7 @@ static void gfs2_evict_inode(struct inode *inode) truncate_inode_pages_final(&inode->i_data); if (ip->i_qadata) gfs2_assert_warn(sdp, ip->i_qadata->qa_ref =3D=3D 0); - gfs2_rs_delete(ip, NULL); + gfs2_rs_deltree(&ip->i_res); gfs2_ordered_del_inode(ip); clear_inode(inode); gfs2_dir_hash_inval(ip); diff --git a/fs/io_uring.c b/fs/io_uring.c index db724482cd11..49cafa0a8b8f 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -2720,8 +2720,12 @@ static bool io_rw_should_reissue(struct io_kiocb *re= q) =20 static bool __io_complete_rw_common(struct io_kiocb *req, long res) { - if (req->rw.kiocb.ki_flags & IOCB_WRITE) + if (req->rw.kiocb.ki_flags & IOCB_WRITE) { kiocb_end_write(req); + fsnotify_modify(req->file); + } else { + fsnotify_access(req->file); + } if (unlikely(res !=3D req->result)) { if ((res =3D=3D -EAGAIN || res =3D=3D -EOPNOTSUPP) && io_rw_should_reissue(req)) { @@ -3346,13 +3350,15 @@ static ssize_t loop_rw_iter(int rw, struct io_kiocb= *req, struct iov_iter *iter) ret =3D nr; break; } + ret +=3D nr; if (!iov_iter_is_bvec(iter)) { iov_iter_advance(iter, nr); } else { - req->rw.len -=3D nr; req->rw.addr +=3D nr; + req->rw.len -=3D nr; + if (!req->rw.len) + break; } - ret +=3D nr; if (nr !=3D iovec.iov_len) break; } @@ -4211,6 +4217,8 @@ static int io_fallocate(struct io_kiocb *req, unsigne= d int issue_flags) req->sync.len); if (ret < 0) req_set_fail(req); + else + fsnotify_modify(req->file); io_req_complete(req, ret); return 0; } @@ -5172,8 +5180,7 @@ static int io_accept_prep(struct io_kiocb *req, const= struct io_uring_sqe *sqe) accept->nofile =3D rlimit(RLIMIT_NOFILE); =20 accept->file_slot =3D READ_ONCE(sqe->file_index); - if (accept->file_slot && ((req->open.how.flags & O_CLOEXEC) || - (accept->flags & SOCK_CLOEXEC))) + if (accept->file_slot && (accept->flags & SOCK_CLOEXEC)) return -EINVAL; if (accept->flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) return -EINVAL; @@ -8173,6 +8180,7 @@ static int __io_sqe_files_scm(struct io_ring_ctx *ctx= , int nr, int offset) fput(fpl->fp[i]); } else { kfree_skb(skb); + free_uid(fpl->user); kfree(fpl); } =20 diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index b288c8ae1236..837cd55fd4c5 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c @@ -415,13 +415,15 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c) jffs2_free_ino_caches(c); jffs2_free_raw_node_refs(c); ret =3D -EIO; - goto out_free; + goto out_sum_exit; } =20 jffs2_calc_trigger_levels(c); =20 return 0; =20 + out_sum_exit: + jffs2_sum_exit(c); out_free: kvfree(c->blocks); =20 diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 2ac410477c4f..71f03a5d36ed 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -603,8 +603,8 @@ int jffs2_do_fill_super(struct super_block *sb, struct = fs_context *fc) jffs2_free_ino_caches(c); jffs2_free_raw_node_refs(c); kvfree(c->blocks); - out_inohash: jffs2_clear_xattr_subsystem(c); + out_inohash: kfree(c->inocache_list); out_wbuf: jffs2_flash_cleanup(c); diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index b676056826be..29671e33a171 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -136,7 +136,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) if (!s) { JFFS2_WARNING("Can't allocate memory for summary\n"); ret =3D -ENOMEM; - goto out; + goto out_buf; } } =20 @@ -275,13 +275,15 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) } ret =3D 0; out: + jffs2_sum_reset_collected(s); + kfree(s); + out_buf: if (buf_size) kfree(flashbuf); #ifndef __ECOS else mtd_unpoint(c->mtd, 0, c->mtd->size); #endif - kfree(s); return ret; } =20 diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index 91f4ec93dab1..d8502f4989d9 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -148,6 +148,7 @@ static const s8 budtab[256] =3D { * 0 - success * -ENOMEM - insufficient memory * -EIO - i/o error + * -EINVAL - wrong bmap data */ int dbMount(struct inode *ipbmap) { @@ -179,6 +180,12 @@ int dbMount(struct inode *ipbmap) bmp->db_nfree =3D le64_to_cpu(dbmp_le->dn_nfree); bmp->db_l2nbperpage =3D le32_to_cpu(dbmp_le->dn_l2nbperpage); bmp->db_numag =3D le32_to_cpu(dbmp_le->dn_numag); + if (!bmp->db_numag) { + release_metapage(mp); + kfree(bmp); + return -EINVAL; + } + bmp->db_maxlevel =3D le32_to_cpu(dbmp_le->dn_maxlevel); bmp->db_maxag =3D le32_to_cpu(dbmp_le->dn_maxag); bmp->db_agpref =3D le32_to_cpu(dbmp_le->dn_agpref); diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index c343666d9a42..6464dde03705 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -358,12 +358,11 @@ __be32 nfs4_callback_devicenotify(void *argp, void *r= esp, struct cb_process_state *cps) { struct cb_devicenotifyargs *args =3D argp; + const struct pnfs_layoutdriver_type *ld =3D NULL; uint32_t i; __be32 res =3D 0; - struct nfs_client *clp =3D cps->clp; - struct nfs_server *server =3D NULL; =20 - if (!clp) { + if (!cps->clp) { res =3D cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION); goto out; } @@ -371,23 +370,15 @@ __be32 nfs4_callback_devicenotify(void *argp, void *r= esp, for (i =3D 0; i < args->ndevs; i++) { struct cb_devicenotifyitem *dev =3D &args->devs[i]; =20 - if (!server || - server->pnfs_curr_ld->id !=3D dev->cbd_layout_type) { - rcu_read_lock(); - list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) - if (server->pnfs_curr_ld && - server->pnfs_curr_ld->id =3D=3D dev->cbd_layout_type) { - rcu_read_unlock(); - goto found; - } - rcu_read_unlock(); - continue; + if (!ld || ld->id !=3D dev->cbd_layout_type) { + pnfs_put_layoutdriver(ld); + ld =3D pnfs_find_layoutdriver(dev->cbd_layout_type); + if (!ld) + continue; } - - found: - nfs4_delete_deviceid(server->pnfs_curr_ld, clp, &dev->cbd_dev_id); + nfs4_delete_deviceid(ld, cps->clp, &dev->cbd_dev_id); } - + pnfs_put_layoutdriver(ld); out: kfree(args->devs); return res; diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index f90de8043b0f..8dcb08e1a885 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -271,10 +271,6 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp, n =3D ntohl(*p++); if (n =3D=3D 0) goto out; - if (n > ULONG_MAX / sizeof(*args->devs)) { - status =3D htonl(NFS4ERR_BADXDR); - goto out; - } =20 args->devs =3D kmalloc_array(n, sizeof(*args->devs), GFP_KERNEL); if (!args->devs) { diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 7fba7711e6b3..3d5ba43f44bb 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -949,7 +949,7 @@ int nfs2_decode_dirent(struct xdr_stream *xdr, struct n= fs_entry *entry, =20 error =3D decode_filename_inline(xdr, &entry->name, &entry->len); if (unlikely(error)) - return error; + return -EAGAIN; =20 /* * The type (size and byte order) of nfscookie isn't defined in diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 9274c9c5efea..7ab60ad98776 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -1967,7 +1967,6 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct= nfs_entry *entry, bool plus) { struct user_namespace *userns =3D rpc_userns(entry->server->client); - struct nfs_entry old =3D *entry; __be32 *p; int error; u64 new_cookie; @@ -1987,15 +1986,15 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, stru= ct nfs_entry *entry, =20 error =3D decode_fileid3(xdr, &entry->ino); if (unlikely(error)) - return error; + return -EAGAIN; =20 error =3D decode_inline_filename3(xdr, &entry->name, &entry->len); if (unlikely(error)) - return error; + return -EAGAIN; =20 error =3D decode_cookie3(xdr, &new_cookie); if (unlikely(error)) - return error; + return -EAGAIN; =20 entry->d_type =3D DT_UNKNOWN; =20 @@ -2003,7 +2002,7 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct= nfs_entry *entry, entry->fattr->valid =3D 0; error =3D decode_post_op_attr(xdr, entry->fattr, userns); if (unlikely(error)) - return error; + return -EAGAIN; if (entry->fattr->valid & NFS_ATTR_FATTR_V3) entry->d_type =3D nfs_umode_to_dtype(entry->fattr->mode); =20 @@ -2018,11 +2017,8 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struc= t nfs_entry *entry, return -EAGAIN; if (*p !=3D xdr_zero) { error =3D decode_nfs_fh3(xdr, entry->fh); - if (unlikely(error)) { - if (error =3D=3D -E2BIG) - goto out_truncated; - return error; - } + if (unlikely(error)) + return -EAGAIN; } else zero_nfs_fh3(entry->fh); } @@ -2031,11 +2027,6 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struc= t nfs_entry *entry, entry->cookie =3D new_cookie; =20 return 0; - -out_truncated: - dprintk("NFS: directory entry contains invalid file handle\n"); - *entry =3D old; - return -EAGAIN; } =20 /* @@ -2228,6 +2219,7 @@ static int decode_fsinfo3resok(struct xdr_stream *xdr, /* ignore properties */ result->lease_time =3D 0; result->change_attr_type =3D NFS4_CHANGE_TYPE_IS_UNDEFINED; + result->xattr_support =3D 0; return 0; } =20 diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 0abbbf5d2bdf..5298c3a278c5 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -8275,6 +8275,7 @@ nfs4_bind_one_conn_to_session_done(struct rpc_task *t= ask, void *calldata) case -NFS4ERR_DEADSESSION: nfs4_schedule_session_recovery(clp->cl_session, task->tk_status); + return; } if (args->dir =3D=3D NFS4_CDFC4_FORE_OR_BOTH && res->dir !=3D NFS4_CDFS4_BOTH) { diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index ad7f83dc9a2d..815d63080245 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -1218,6 +1218,7 @@ static int nfs_do_recoalesce(struct nfs_pageio_descri= ptor *desc) =20 do { list_splice_init(&mirror->pg_list, &head); + mirror->pg_recoalesce =3D 0; =20 while (!list_empty(&head)) { struct nfs_page *req; diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 7c9090a28e5c..7ddd003ab8b1 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -92,6 +92,17 @@ find_pnfs_driver(u32 id) return local; } =20 +const struct pnfs_layoutdriver_type *pnfs_find_layoutdriver(u32 id) +{ + return find_pnfs_driver(id); +} + +void pnfs_put_layoutdriver(const struct pnfs_layoutdriver_type *ld) +{ + if (ld) + module_put(ld->owner); +} + void unset_pnfs_layoutdriver(struct nfs_server *nfss) { diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index f4d7548d67b2..07f11489e4e9 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -234,6 +234,8 @@ struct pnfs_devicelist { =20 extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *); extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *); +extern const struct pnfs_layoutdriver_type *pnfs_find_layoutdriver(u32 id); +extern void pnfs_put_layoutdriver(const struct pnfs_layoutdriver_type *ld); =20 /* nfs4proc.c */ extern size_t max_response_pages(struct nfs_server *server); diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 73dcaa99fa9b..e3570c656b0f 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -92,6 +92,7 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_f= h *fhandle, info->maxfilesize =3D 0x7FFFFFFF; info->lease_time =3D 0; info->change_attr_type =3D NFS4_CHANGE_TYPE_IS_UNDEFINED; + info->xattr_support =3D 0; return 0; } =20 diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 9b7619ce17a7..e86aff429993 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -315,7 +315,10 @@ static void nfs_mapping_set_error(struct page *page, i= nt error) struct address_space *mapping =3D page_file_mapping(page); =20 SetPageError(page); - mapping_set_error(mapping, error); + filemap_set_wb_err(mapping, error); + if (mapping->host) + errseq_set(&mapping->host->i_sb->s_wb_err, + error =3D=3D -ENOSPC ? -ENOSPC : -EIO); nfs_set_pageerror(mapping); } =20 @@ -1408,6 +1411,8 @@ static void nfs_initiate_write(struct nfs_pgio_header= *hdr, { int priority =3D flush_task_priority(how); =20 + if (IS_SWAPFILE(hdr->inode)) + task_setup_data->flags |=3D RPC_TASK_SWAPPER; task_setup_data->priority =3D priority; rpc_ops->write_setup(hdr, msg, &task_setup_data->rpc_client); trace_nfs_initiate_write(hdr); diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c index fdf89fcf1a0c..4cffe05e0477 100644 --- a/fs/nfsd/filecache.c +++ b/fs/nfsd/filecache.c @@ -644,7 +644,7 @@ nfsd_file_cache_init(void) if (!nfsd_filecache_wq) goto out; =20 - nfsd_file_hashtbl =3D kcalloc(NFSD_FILE_HASH_SIZE, + nfsd_file_hashtbl =3D kvcalloc(NFSD_FILE_HASH_SIZE, sizeof(*nfsd_file_hashtbl), GFP_KERNEL); if (!nfsd_file_hashtbl) { pr_err("nfsd: unable to allocate nfsd_file_hashtbl\n"); @@ -712,7 +712,7 @@ nfsd_file_cache_init(void) nfsd_file_slab =3D NULL; kmem_cache_destroy(nfsd_file_mark_slab); nfsd_file_mark_slab =3D NULL; - kfree(nfsd_file_hashtbl); + kvfree(nfsd_file_hashtbl); nfsd_file_hashtbl =3D NULL; destroy_workqueue(nfsd_filecache_wq); nfsd_filecache_wq =3D NULL; @@ -858,7 +858,7 @@ nfsd_file_cache_shutdown(void) fsnotify_wait_marks_destroyed(); kmem_cache_destroy(nfsd_file_mark_slab); nfsd_file_mark_slab =3D NULL; - kfree(nfsd_file_hashtbl); + kvfree(nfsd_file_hashtbl); nfsd_file_hashtbl =3D NULL; destroy_workqueue(nfsd_filecache_wq); nfsd_filecache_wq =3D NULL; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index ac0ddde8beef..6075a328d756 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4693,6 +4693,14 @@ nfsd_break_deleg_cb(struct file_lock *fl) return ret; } =20 +/** + * nfsd_breaker_owns_lease - Check if lease conflict was resolved + * @fl: Lock state to check + * + * Return values: + * %true: Lease conflict was resolved + * %false: Lease conflict was not resolved. + */ static bool nfsd_breaker_owns_lease(struct file_lock *fl) { struct nfs4_delegation *dl =3D fl->fl_owner; @@ -4700,11 +4708,11 @@ static bool nfsd_breaker_owns_lease(struct file_loc= k *fl) struct nfs4_client *clp; =20 if (!i_am_nfsd()) - return NULL; + return false; rqst =3D kthread_data(current); /* Note rq_prog =3D=3D NFS_ACL_PROGRAM is also possible: */ if (rqst->rq_prog !=3D NFS_PROGRAM || rqst->rq_vers < 4) - return NULL; + return false; clp =3D *(rqst->rq_lease_breaker); return dl->dl_stid.sc_client =3D=3D clp; } diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 312fd289be58..9700ad433b49 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -230,7 +230,7 @@ nfsd_proc_write(struct svc_rqst *rqstp) unsigned long cnt =3D argp->len; unsigned int nvecs; =20 - dprintk("nfsd: WRITE %s %d bytes at %d\n", + dprintk("nfsd: WRITE %s %u bytes at %d\n", SVCFH_fmt(&argp->fh), argp->len, argp->offset); =20 diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h index 528fb299430e..852f71580bd0 100644 --- a/fs/nfsd/xdr.h +++ b/fs/nfsd/xdr.h @@ -32,7 +32,7 @@ struct nfsd_readargs { struct nfsd_writeargs { svc_fh fh; __u32 offset; - int len; + __u32 len; struct xdr_buf payload; }; =20 diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 4474adb393ca..517b71c73aa9 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -1881,6 +1881,10 @@ int ntfs_read_inode_mount(struct inode *vi) } /* Now allocate memory for the attribute list. */ ni->attr_list_size =3D (u32)ntfs_attr_size(a); + if (!ni->attr_list_size) { + ntfs_error(sb, "Attr_list_size is zero"); + goto put_err_out; + } ni->attr_list =3D ntfs_malloc_nofs(ni->attr_list_size); if (!ni->attr_list) { ntfs_error(sb, "Not enough memory to allocate buffer " diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c index f033de733adb..effe92c7d693 100644 --- a/fs/ocfs2/quota_global.c +++ b/fs/ocfs2/quota_global.c @@ -337,7 +337,6 @@ void ocfs2_unlock_global_qf(struct ocfs2_mem_dqinfo *oi= nfo, int ex) /* Read information header from global quota file */ int ocfs2_global_read_info(struct super_block *sb, int type) { - struct inode *gqinode =3D NULL; unsigned int ino[OCFS2_MAXQUOTAS] =3D { USER_QUOTA_SYSTEM_INODE, GROUP_QUOTA_SYSTEM_INODE }; struct ocfs2_global_disk_dqinfo dinfo; @@ -346,29 +345,31 @@ int ocfs2_global_read_info(struct super_block *sb, in= t type) u64 pcount; int status; =20 + oinfo->dqi_gi.dqi_sb =3D sb; + oinfo->dqi_gi.dqi_type =3D type; + ocfs2_qinfo_lock_res_init(&oinfo->dqi_gqlock, oinfo); + oinfo->dqi_gi.dqi_entry_size =3D sizeof(struct ocfs2_global_disk_dqblk); + oinfo->dqi_gi.dqi_ops =3D &ocfs2_global_ops; + oinfo->dqi_gqi_bh =3D NULL; + oinfo->dqi_gqi_count =3D 0; + /* Read global header */ - gqinode =3D ocfs2_get_system_file_inode(OCFS2_SB(sb), ino[type], + oinfo->dqi_gqinode =3D ocfs2_get_system_file_inode(OCFS2_SB(sb), ino[type= ], OCFS2_INVALID_SLOT); - if (!gqinode) { + if (!oinfo->dqi_gqinode) { mlog(ML_ERROR, "failed to get global quota inode (type=3D%d)\n", type); status =3D -EINVAL; goto out_err; } - oinfo->dqi_gi.dqi_sb =3D sb; - oinfo->dqi_gi.dqi_type =3D type; - oinfo->dqi_gi.dqi_entry_size =3D sizeof(struct ocfs2_global_disk_dqblk); - oinfo->dqi_gi.dqi_ops =3D &ocfs2_global_ops; - oinfo->dqi_gqi_bh =3D NULL; - oinfo->dqi_gqi_count =3D 0; - oinfo->dqi_gqinode =3D gqinode; + status =3D ocfs2_lock_global_qf(oinfo, 0); if (status < 0) { mlog_errno(status); goto out_err; } =20 - status =3D ocfs2_extent_map_get_blocks(gqinode, 0, &oinfo->dqi_giblk, + status =3D ocfs2_extent_map_get_blocks(oinfo->dqi_gqinode, 0, &oinfo->dqi= _giblk, &pcount, NULL); if (status < 0) goto out_unlock; diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c index 0e4b16d4c037..b1a8b046f4c2 100644 --- a/fs/ocfs2/quota_local.c +++ b/fs/ocfs2/quota_local.c @@ -702,8 +702,6 @@ static int ocfs2_local_read_info(struct super_block *sb= , int type) info->dqi_priv =3D oinfo; oinfo->dqi_type =3D type; INIT_LIST_HEAD(&oinfo->dqi_chunk); - oinfo->dqi_gqinode =3D NULL; - ocfs2_qinfo_lock_res_init(&oinfo->dqi_gqlock, oinfo); oinfo->dqi_rec =3D NULL; oinfo->dqi_lqi_bh =3D NULL; oinfo->dqi_libh =3D NULL; diff --git a/fs/proc/bootconfig.c b/fs/proc/bootconfig.c index 6d8d4bf20837..2e244ada1f97 100644 --- a/fs/proc/bootconfig.c +++ b/fs/proc/bootconfig.c @@ -32,6 +32,8 @@ static int __init copy_xbc_key_value_list(char *dst, size= _t size) int ret =3D 0; =20 key =3D kzalloc(XBC_KEYLEN_MAX, GFP_KERNEL); + if (!key) + return -ENOMEM; =20 xbc_for_each_key_value(leaf, val) { ret =3D xbc_node_compose_key(leaf, key, XBC_KEYLEN_MAX); diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index f243cb5e6a4f..e26162f102ff 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -143,21 +143,22 @@ static void pstore_timer_kick(void) mod_timer(&pstore_timer, jiffies + msecs_to_jiffies(pstore_update_ms)); } =20 -/* - * Should pstore_dump() wait for a concurrent pstore_dump()? If - * not, the current pstore_dump() will report a failure to dump - * and return. - */ -static bool pstore_cannot_wait(enum kmsg_dump_reason reason) +static bool pstore_cannot_block_path(enum kmsg_dump_reason reason) { - /* In NMI path, pstore shouldn't block regardless of reason. */ + /* + * In case of NMI path, pstore shouldn't be blocked + * regardless of reason. + */ if (in_nmi()) return true; =20 switch (reason) { /* In panic case, other cpus are stopped by smp_send_stop(). */ case KMSG_DUMP_PANIC: - /* Emergency restart shouldn't be blocked. */ + /* + * Emergency restart shouldn't be blocked by spinning on + * pstore_info::buf_lock. + */ case KMSG_DUMP_EMERG: return true; default: @@ -389,21 +390,19 @@ static void pstore_dump(struct kmsg_dumper *dumper, unsigned long total =3D 0; const char *why; unsigned int part =3D 1; + unsigned long flags =3D 0; int ret; =20 why =3D kmsg_dump_reason_str(reason); =20 - if (down_trylock(&psinfo->buf_lock)) { - /* Failed to acquire lock: give up if we cannot wait. */ - if (pstore_cannot_wait(reason)) { - pr_err("dump skipped in %s path: may corrupt error record\n", - in_nmi() ? "NMI" : why); - return; - } - if (down_interruptible(&psinfo->buf_lock)) { - pr_err("could not grab semaphore?!\n"); + if (pstore_cannot_block_path(reason)) { + if (!spin_trylock_irqsave(&psinfo->buf_lock, flags)) { + pr_err("dump skipped in %s path because of concurrent dump\n", + in_nmi() ? "NMI" : why); return; } + } else { + spin_lock_irqsave(&psinfo->buf_lock, flags); } =20 kmsg_dump_rewind(&iter); @@ -467,8 +466,7 @@ static void pstore_dump(struct kmsg_dumper *dumper, total +=3D record.size; part++; } - - up(&psinfo->buf_lock); + spin_unlock_irqrestore(&psinfo->buf_lock, flags); } =20 static struct kmsg_dumper pstore_dumper =3D { @@ -594,7 +592,7 @@ int pstore_register(struct pstore_info *psi) psi->write_user =3D pstore_write_user_compat; psinfo =3D psi; mutex_init(&psinfo->read_mutex); - sema_init(&psinfo->buf_lock, 1); + spin_lock_init(&psinfo->buf_lock); =20 if (psi->flags & PSTORE_FLAGS_DMESG) allocate_buf_for_compression(); diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 7c61d0ec0159..79e371bc15e1 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -349,20 +349,97 @@ static int ubifs_create(struct user_namespace *mnt_us= erns, struct inode *dir, return err; } =20 -static int do_tmpfile(struct inode *dir, struct dentry *dentry, - umode_t mode, struct inode **whiteout) +static struct inode *create_whiteout(struct inode *dir, struct dentry *den= try) +{ + int err; + umode_t mode =3D S_IFCHR | WHITEOUT_MODE; + struct inode *inode; + struct ubifs_info *c =3D dir->i_sb->s_fs_info; + struct fscrypt_name nm; + + /* + * Create an inode('nlink =3D 1') for whiteout without updating journal, + * let ubifs_jnl_rename() store it on flash to complete rename whiteout + * atomically. + */ + + dbg_gen("dent '%pd', mode %#hx in dir ino %lu", + dentry, mode, dir->i_ino); + + err =3D fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm); + if (err) + return ERR_PTR(err); + + inode =3D ubifs_new_inode(c, dir, mode); + if (IS_ERR(inode)) { + err =3D PTR_ERR(inode); + goto out_free; + } + + init_special_inode(inode, inode->i_mode, WHITEOUT_DEV); + ubifs_assert(c, inode->i_op =3D=3D &ubifs_file_inode_operations); + + err =3D ubifs_init_security(dir, inode, &dentry->d_name); + if (err) + goto out_inode; + + /* The dir size is updated by do_rename. */ + insert_inode_hash(inode); + + return inode; + +out_inode: + make_bad_inode(inode); + iput(inode); +out_free: + fscrypt_free_filename(&nm); + ubifs_err(c, "cannot create whiteout file, error %d", err); + return ERR_PTR(err); +} + +/** + * lock_2_inodes - a wrapper for locking two UBIFS inodes. + * @inode1: first inode + * @inode2: second inode + * + * We do not implement any tricks to guarantee strict lock ordering, becau= se + * VFS has already done it for us on the @i_mutex. So this is just a simple + * wrapper function. + */ +static void lock_2_inodes(struct inode *inode1, struct inode *inode2) +{ + mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1); + mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2); +} + +/** + * unlock_2_inodes - a wrapper for unlocking two UBIFS inodes. + * @inode1: first inode + * @inode2: second inode + */ +static void unlock_2_inodes(struct inode *inode1, struct inode *inode2) +{ + mutex_unlock(&ubifs_inode(inode2)->ui_mutex); + mutex_unlock(&ubifs_inode(inode1)->ui_mutex); +} + +static int ubifs_tmpfile(struct user_namespace *mnt_userns, struct inode *= dir, + struct dentry *dentry, umode_t mode) { struct inode *inode; struct ubifs_info *c =3D dir->i_sb->s_fs_info; - struct ubifs_budget_req req =3D { .new_ino =3D 1, .new_dent =3D 1}; + struct ubifs_budget_req req =3D { .new_ino =3D 1, .new_dent =3D 1, + .dirtied_ino =3D 1}; struct ubifs_budget_req ino_req =3D { .dirtied_ino =3D 1 }; - struct ubifs_inode *ui, *dir_ui =3D ubifs_inode(dir); + struct ubifs_inode *ui; int err, instantiated =3D 0; struct fscrypt_name nm; =20 /* - * Budget request settings: new dirty inode, new direntry, - * budget for dirtied inode will be released via writeback. + * Budget request settings: new inode, new direntry, changing the + * parent directory inode. + * Allocate budget separately for new dirtied inode, the budget will + * be released via writeback. */ =20 dbg_gen("dent '%pd', mode %#hx in dir ino %lu", @@ -392,42 +469,30 @@ static int do_tmpfile(struct inode *dir, struct dentr= y *dentry, } ui =3D ubifs_inode(inode); =20 - if (whiteout) { - init_special_inode(inode, inode->i_mode, WHITEOUT_DEV); - ubifs_assert(c, inode->i_op =3D=3D &ubifs_file_inode_operations); - } - err =3D ubifs_init_security(dir, inode, &dentry->d_name); if (err) goto out_inode; =20 mutex_lock(&ui->ui_mutex); insert_inode_hash(inode); - - if (whiteout) { - mark_inode_dirty(inode); - drop_nlink(inode); - *whiteout =3D inode; - } else { - d_tmpfile(dentry, inode); - } + d_tmpfile(dentry, inode); ubifs_assert(c, ui->dirty); =20 instantiated =3D 1; mutex_unlock(&ui->ui_mutex); =20 - mutex_lock(&dir_ui->ui_mutex); + lock_2_inodes(dir, inode); err =3D ubifs_jnl_update(c, dir, &nm, inode, 1, 0); if (err) goto out_cancel; - mutex_unlock(&dir_ui->ui_mutex); + unlock_2_inodes(dir, inode); =20 ubifs_release_budget(c, &req); =20 return 0; =20 out_cancel: - mutex_unlock(&dir_ui->ui_mutex); + unlock_2_inodes(dir, inode); out_inode: make_bad_inode(inode); if (!instantiated) @@ -441,12 +506,6 @@ static int do_tmpfile(struct inode *dir, struct dentry= *dentry, return err; } =20 -static int ubifs_tmpfile(struct user_namespace *mnt_userns, struct inode *= dir, - struct dentry *dentry, umode_t mode) -{ - return do_tmpfile(dir, dentry, mode, NULL); -} - /** * vfs_dent_type - get VFS directory entry type. * @type: UBIFS directory entry type @@ -660,32 +719,6 @@ static int ubifs_dir_release(struct inode *dir, struct= file *file) return 0; } =20 -/** - * lock_2_inodes - a wrapper for locking two UBIFS inodes. - * @inode1: first inode - * @inode2: second inode - * - * We do not implement any tricks to guarantee strict lock ordering, becau= se - * VFS has already done it for us on the @i_mutex. So this is just a simple - * wrapper function. - */ -static void lock_2_inodes(struct inode *inode1, struct inode *inode2) -{ - mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1); - mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2); -} - -/** - * unlock_2_inodes - a wrapper for unlocking two UBIFS inodes. - * @inode1: first inode - * @inode2: second inode - */ -static void unlock_2_inodes(struct inode *inode1, struct inode *inode2) -{ - mutex_unlock(&ubifs_inode(inode2)->ui_mutex); - mutex_unlock(&ubifs_inode(inode1)->ui_mutex); -} - static int ubifs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { @@ -949,7 +982,8 @@ static int ubifs_mkdir(struct user_namespace *mnt_usern= s, struct inode *dir, struct ubifs_inode *dir_ui =3D ubifs_inode(dir); struct ubifs_info *c =3D dir->i_sb->s_fs_info; int err, sz_change; - struct ubifs_budget_req req =3D { .new_ino =3D 1, .new_dent =3D 1 }; + struct ubifs_budget_req req =3D { .new_ino =3D 1, .new_dent =3D 1, + .dirtied_ino =3D 1}; struct fscrypt_name nm; =20 /* @@ -1264,17 +1298,19 @@ static int do_rename(struct inode *old_dir, struct = dentry *old_dentry, .dirtied_ino =3D 3 }; struct ubifs_budget_req ino_req =3D { .dirtied_ino =3D 1, .dirtied_ino_d =3D ALIGN(old_inode_ui->data_len, 8) }; + struct ubifs_budget_req wht_req; struct timespec64 time; unsigned int saved_nlink; struct fscrypt_name old_nm, new_nm; =20 /* - * Budget request settings: deletion direntry, new direntry, removing - * the old inode, and changing old and new parent directory inodes. + * Budget request settings: + * req: deletion direntry, new direntry, removing the old inode, + * and changing old and new parent directory inodes. + * + * wht_req: new whiteout inode for RENAME_WHITEOUT. * - * However, this operation also marks the target inode as dirty and - * does not write it, so we allocate budget for the target inode - * separately. + * ino_req: marks the target inode as dirty and does not write it. */ =20 dbg_gen("dent '%pd' ino %lu in dir ino %lu to dent '%pd' in dir ino %lu f= lags 0x%x", @@ -1331,20 +1367,44 @@ static int do_rename(struct inode *old_dir, struct = dentry *old_dentry, goto out_release; } =20 - err =3D do_tmpfile(old_dir, old_dentry, S_IFCHR | WHITEOUT_MODE, &whiteo= ut); - if (err) { + /* + * The whiteout inode without dentry is pinned in memory, + * umount won't happen during rename process because we + * got parent dentry. + */ + whiteout =3D create_whiteout(old_dir, old_dentry); + if (IS_ERR(whiteout)) { + err =3D PTR_ERR(whiteout); kfree(dev); goto out_release; } =20 - spin_lock(&whiteout->i_lock); - whiteout->i_state |=3D I_LINKABLE; - spin_unlock(&whiteout->i_lock); - whiteout_ui =3D ubifs_inode(whiteout); whiteout_ui->data =3D dev; whiteout_ui->data_len =3D ubifs_encode_dev(dev, MKDEV(0, 0)); ubifs_assert(c, !whiteout_ui->dirty); + + memset(&wht_req, 0, sizeof(struct ubifs_budget_req)); + wht_req.new_ino =3D 1; + wht_req.new_ino_d =3D ALIGN(whiteout_ui->data_len, 8); + /* + * To avoid deadlock between space budget (holds ui_mutex and + * waits wb work) and writeback work(waits ui_mutex), do space + * budget before ubifs inodes locked. + */ + err =3D ubifs_budget_space(c, &wht_req); + if (err) { + /* + * Whiteout inode can not be written on flash by + * ubifs_jnl_write_inode(), because it's neither + * dirty nor zero-nlink. + */ + iput(whiteout); + goto out_release; + } + + /* Add the old_dentry size to the old_dir size. */ + old_sz -=3D CALC_DENT_SIZE(fname_len(&old_nm)); } =20 lock_4_inodes(old_dir, new_dir, new_inode, whiteout); @@ -1416,29 +1476,11 @@ static int do_rename(struct inode *old_dir, struct = dentry *old_dentry, sync =3D IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir); if (unlink && IS_SYNC(new_inode)) sync =3D 1; - } - - if (whiteout) { - struct ubifs_budget_req wht_req =3D { .dirtied_ino =3D 1, - .dirtied_ino_d =3D \ - ALIGN(ubifs_inode(whiteout)->data_len, 8) }; - - err =3D ubifs_budget_space(c, &wht_req); - if (err) { - kfree(whiteout_ui->data); - whiteout_ui->data_len =3D 0; - iput(whiteout); - goto out_release; - } - - inc_nlink(whiteout); - mark_inode_dirty(whiteout); - - spin_lock(&whiteout->i_lock); - whiteout->i_state &=3D ~I_LINKABLE; - spin_unlock(&whiteout->i_lock); - - iput(whiteout); + /* + * S_SYNC flag of whiteout inherits from the old_dir, and we + * have already checked the old dir inode. So there is no need + * to check whiteout. + */ } =20 err =3D ubifs_jnl_rename(c, old_dir, old_inode, &old_nm, new_dir, @@ -1449,6 +1491,11 @@ static int do_rename(struct inode *old_dir, struct d= entry *old_dentry, unlock_4_inodes(old_dir, new_dir, new_inode, whiteout); ubifs_release_budget(c, &req); =20 + if (whiteout) { + ubifs_release_budget(c, &wht_req); + iput(whiteout); + } + mutex_lock(&old_inode_ui->ui_mutex); release =3D old_inode_ui->dirty; mark_inode_dirty_sync(old_inode); @@ -1457,11 +1504,16 @@ static int do_rename(struct inode *old_dir, struct = dentry *old_dentry, if (release) ubifs_release_budget(c, &ino_req); if (IS_SYNC(old_inode)) - err =3D old_inode->i_sb->s_op->write_inode(old_inode, NULL); + /* + * Rename finished here. Although old inode cannot be updated + * on flash, old ctime is not a big problem, don't return err + * code to userspace. + */ + old_inode->i_sb->s_op->write_inode(old_inode, NULL); =20 fscrypt_free_filename(&old_nm); fscrypt_free_filename(&new_nm); - return err; + return 0; =20 out_cancel: if (unlink) { @@ -1482,11 +1534,11 @@ static int do_rename(struct inode *old_dir, struct = dentry *old_dentry, inc_nlink(old_dir); } } + unlock_4_inodes(old_dir, new_dir, new_inode, whiteout); if (whiteout) { - drop_nlink(whiteout); + ubifs_release_budget(c, &wht_req); iput(whiteout); } - unlock_4_inodes(old_dir, new_dir, new_inode, whiteout); out_release: ubifs_release_budget(c, &ino_req); ubifs_release_budget(c, &req); diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 5cfa28cd00cd..6b45a037a047 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -570,7 +570,7 @@ static int ubifs_write_end(struct file *file, struct ad= dress_space *mapping, } =20 if (!PagePrivate(page)) { - SetPagePrivate(page); + attach_page_private(page, (void *)1); atomic_long_inc(&c->dirty_pg_cnt); __set_page_dirty_nobuffers(page); } @@ -947,7 +947,7 @@ static int do_writepage(struct page *page, int len) release_existing_page_budget(c); =20 atomic_long_dec(&c->dirty_pg_cnt); - ClearPagePrivate(page); + detach_page_private(page); ClearPageChecked(page); =20 kunmap(page); @@ -1304,7 +1304,7 @@ static void ubifs_invalidatepage(struct page *page, u= nsigned int offset, release_existing_page_budget(c); =20 atomic_long_dec(&c->dirty_pg_cnt); - ClearPagePrivate(page); + detach_page_private(page); ClearPageChecked(page); } =20 @@ -1471,8 +1471,8 @@ static int ubifs_migrate_page(struct address_space *m= apping, return rc; =20 if (PagePrivate(page)) { - ClearPagePrivate(page); - SetPagePrivate(newpage); + detach_page_private(page); + attach_page_private(newpage, (void *)1); } =20 if (mode !=3D MIGRATE_SYNC_NO_COPY) @@ -1496,7 +1496,7 @@ static int ubifs_releasepage(struct page *page, gfp_t= unused_gfp_flags) return 0; ubifs_assert(c, PagePrivate(page)); ubifs_assert(c, 0); - ClearPagePrivate(page); + detach_page_private(page); ClearPageChecked(page); return 1; } @@ -1567,7 +1567,7 @@ static vm_fault_t ubifs_vm_page_mkwrite(struct vm_fau= lt *vmf) else { if (!PageChecked(page)) ubifs_convert_page_budget(c); - SetPagePrivate(page); + attach_page_private(page, (void *)1); atomic_long_inc(&c->dirty_pg_cnt); __set_page_dirty_nobuffers(page); } diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c index 00b61dba62b7..b019dd6f7fa0 100644 --- a/fs/ubifs/io.c +++ b/fs/ubifs/io.c @@ -833,16 +833,42 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, = void *buf, int len) */ n =3D aligned_len >> c->max_write_shift; if (n) { - n <<=3D c->max_write_shift; + int m =3D n - 1; + dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum, wbuf->offs); - err =3D ubifs_leb_write(c, wbuf->lnum, buf + written, - wbuf->offs, n); + + if (m) { + /* '(n-1)<max_write_shift < len' is always true. */ + m <<=3D c->max_write_shift; + err =3D ubifs_leb_write(c, wbuf->lnum, buf + written, + wbuf->offs, m); + if (err) + goto out; + wbuf->offs +=3D m; + aligned_len -=3D m; + len -=3D m; + written +=3D m; + } + + /* + * The non-written len of buf may be less than 'n' because + * parameter 'len' is not 8 bytes aligned, so here we read + * min(len, n) bytes from buf. + */ + n =3D 1 << c->max_write_shift; + memcpy(wbuf->buf, buf + written, min(len, n)); + if (n > len) { + ubifs_assert(c, n - len < 8); + ubifs_pad(c, wbuf->buf + len, n - len); + } + + err =3D ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs, n); if (err) goto out; wbuf->offs +=3D n; aligned_len -=3D n; - len -=3D n; + len -=3D min(len, n); written +=3D n; } =20 diff --git a/fs/ubifs/ioctl.c b/fs/ubifs/ioctl.c index c6a863487780..71bcebe45f9c 100644 --- a/fs/ubifs/ioctl.c +++ b/fs/ubifs/ioctl.c @@ -108,7 +108,7 @@ static int setflags(struct inode *inode, int flags) struct ubifs_inode *ui =3D ubifs_inode(inode); struct ubifs_info *c =3D inode->i_sb->s_fs_info; struct ubifs_budget_req req =3D { .dirtied_ino =3D 1, - .dirtied_ino_d =3D ui->data_len }; + .dirtied_ino_d =3D ALIGN(ui->data_len, 8) }; =20 err =3D ubifs_budget_space(c, &req); if (err) diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c index 8ea680dba61e..75dab0ae3939 100644 --- a/fs/ubifs/journal.c +++ b/fs/ubifs/journal.c @@ -1207,9 +1207,9 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const str= uct inode *fst_dir, * @sync: non-zero if the write-buffer has to be synchronized * * This function implements the re-name operation which may involve writin= g up - * to 4 inodes and 2 directory entries. It marks the written inodes as cle= an - * and returns zero on success. In case of failure, a negative error code = is - * returned. + * to 4 inodes(new inode, whiteout inode, old and new parent directory ino= des) + * and 2 directory entries. It marks the written inodes as clean and retur= ns + * zero on success. In case of failure, a negative error code is returned. */ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, const struct inode *old_inode, @@ -1222,14 +1222,15 @@ int ubifs_jnl_rename(struct ubifs_info *c, const st= ruct inode *old_dir, void *p; union ubifs_key key; struct ubifs_dent_node *dent, *dent2; - int err, dlen1, dlen2, ilen, lnum, offs, len, orphan_added =3D 0; + int err, dlen1, dlen2, ilen, wlen, lnum, offs, len, orphan_added =3D 0; int aligned_dlen1, aligned_dlen2, plen =3D UBIFS_INO_NODE_SZ; int last_reference =3D !!(new_inode && new_inode->i_nlink =3D=3D 0); int move =3D (old_dir !=3D new_dir); - struct ubifs_inode *new_ui; + struct ubifs_inode *new_ui, *whiteout_ui; u8 hash_old_dir[UBIFS_HASH_ARR_SZ]; u8 hash_new_dir[UBIFS_HASH_ARR_SZ]; u8 hash_new_inode[UBIFS_HASH_ARR_SZ]; + u8 hash_whiteout_inode[UBIFS_HASH_ARR_SZ]; u8 hash_dent1[UBIFS_HASH_ARR_SZ]; u8 hash_dent2[UBIFS_HASH_ARR_SZ]; =20 @@ -1249,9 +1250,20 @@ int ubifs_jnl_rename(struct ubifs_info *c, const str= uct inode *old_dir, } else ilen =3D 0; =20 + if (whiteout) { + whiteout_ui =3D ubifs_inode(whiteout); + ubifs_assert(c, mutex_is_locked(&whiteout_ui->ui_mutex)); + ubifs_assert(c, whiteout->i_nlink =3D=3D 1); + ubifs_assert(c, !whiteout_ui->dirty); + wlen =3D UBIFS_INO_NODE_SZ; + wlen +=3D whiteout_ui->data_len; + } else + wlen =3D 0; + aligned_dlen1 =3D ALIGN(dlen1, 8); aligned_dlen2 =3D ALIGN(dlen2, 8); - len =3D aligned_dlen1 + aligned_dlen2 + ALIGN(ilen, 8) + ALIGN(plen, 8); + len =3D aligned_dlen1 + aligned_dlen2 + ALIGN(ilen, 8) + + ALIGN(wlen, 8) + ALIGN(plen, 8); if (move) len +=3D plen; =20 @@ -1313,6 +1325,15 @@ int ubifs_jnl_rename(struct ubifs_info *c, const str= uct inode *old_dir, p +=3D ALIGN(ilen, 8); } =20 + if (whiteout) { + pack_inode(c, p, whiteout, 0); + err =3D ubifs_node_calc_hash(c, p, hash_whiteout_inode); + if (err) + goto out_release; + + p +=3D ALIGN(wlen, 8); + } + if (!move) { pack_inode(c, p, old_dir, 1); err =3D ubifs_node_calc_hash(c, p, hash_old_dir); @@ -1352,6 +1373,9 @@ int ubifs_jnl_rename(struct ubifs_info *c, const stru= ct inode *old_dir, if (new_inode) ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, new_inode->i_ino); + if (whiteout) + ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, + whiteout->i_ino); } release_head(c, BASEHD); =20 @@ -1368,8 +1392,6 @@ int ubifs_jnl_rename(struct ubifs_info *c, const stru= ct inode *old_dir, err =3D ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, hash_dent2, old_nm); if (err) goto out_ro; - - ubifs_delete_orphan(c, whiteout->i_ino); } else { err =3D ubifs_add_dirt(c, lnum, dlen2); if (err) @@ -1390,6 +1412,15 @@ int ubifs_jnl_rename(struct ubifs_info *c, const str= uct inode *old_dir, offs +=3D ALIGN(ilen, 8); } =20 + if (whiteout) { + ino_key_init(c, &key, whiteout->i_ino); + err =3D ubifs_tnc_add(c, &key, lnum, offs, wlen, + hash_whiteout_inode); + if (err) + goto out_ro; + offs +=3D ALIGN(wlen, 8); + } + ino_key_init(c, &key, old_dir->i_ino); err =3D ubifs_tnc_add(c, &key, lnum, offs, plen, hash_old_dir); if (err) @@ -1410,6 +1441,11 @@ int ubifs_jnl_rename(struct ubifs_info *c, const str= uct inode *old_dir, new_ui->synced_i_size =3D new_ui->ui_size; spin_unlock(&new_ui->ui_lock); } + /* + * No need to mark whiteout inode clean. + * Whiteout doesn't have non-zero size, no need to update + * synced_i_size for whiteout_ui. + */ mark_inode_clean(c, ubifs_inode(old_dir)); if (move) mark_inode_clean(c, ubifs_inode(new_dir)); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 379746d3266f..4b45a7d4cb53 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -566,10 +566,16 @@ struct drm_display_info { bool rgb_quant_range_selectable; =20 /** - * @edid_hdmi_dc_modes: Mask of supported hdmi deep color modes. Even - * more stuff redundant with @bus_formats. + * @edid_hdmi_rgb444_dc_modes: Mask of supported hdmi deep color modes + * in RGB 4:4:4. Even more stuff redundant with @bus_formats. */ - u8 edid_hdmi_dc_modes; + u8 edid_hdmi_rgb444_dc_modes; + + /** + * @edid_hdmi_ycbcr444_dc_modes: Mask of supported hdmi deep color + * modes in YCbCr 4:4:4. Even more stuff redundant with @bus_formats. + */ + u8 edid_hdmi_ycbcr444_dc_modes; =20 /** * @cea_rev: CEA revision of the HDMI sink. diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index b52df4db3e8f..99838bdd3350 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -456,7 +456,7 @@ struct drm_panel; #define DP_FEC_CAPABILITY_1 0x091 /* 2.0 */ =20 /* DP-HDMI2.1 PCON DSC ENCODER SUPPORT */ -#define DP_PCON_DSC_ENCODER_CAP_SIZE 0xC /* 0x9E - 0x92 */ +#define DP_PCON_DSC_ENCODER_CAP_SIZE 0xD /* 0x92 through 0x9E */ #define DP_PCON_DSC_ENCODER 0x092 # define DP_PCON_DSC_ENCODER_SUPPORTED (1 << 0) # define DP_PCON_DSC_PPS_ENC_OVERRIDE (1 << 1) diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h index b84693fbd2b5..ec4f543c3d95 100644 --- a/include/drm/drm_modeset_lock.h +++ b/include/drm/drm_modeset_lock.h @@ -34,6 +34,7 @@ struct drm_modeset_lock; * struct drm_modeset_acquire_ctx - locking context (see ww_acquire_ctx) * @ww_ctx: base acquire ctx * @contended: used internally for -EDEADLK handling + * @stack_depot: used internally for contention debugging * @locked: list of held locks * @trylock_only: trylock mode used in atomic contexts/panic notifiers * @interruptible: whether interruptible locking should be used. diff --git a/include/linux/atomic/atomic-arch-fallback.h b/include/linux/at= omic/atomic-arch-fallback.h index a3dba31df01e..6db58d180866 100644 --- a/include/linux/atomic/atomic-arch-fallback.h +++ b/include/linux/atomic/atomic-arch-fallback.h @@ -151,7 +151,16 @@ static __always_inline int arch_atomic_read_acquire(const atomic_t *v) { - return smp_load_acquire(&(v)->counter); + int ret; + + if (__native_word(atomic_t)) { + ret =3D smp_load_acquire(&(v)->counter); + } else { + ret =3D arch_atomic_read(v); + __atomic_acquire_fence(); + } + + return ret; } #define arch_atomic_read_acquire arch_atomic_read_acquire #endif @@ -160,7 +169,12 @@ arch_atomic_read_acquire(const atomic_t *v) static __always_inline void arch_atomic_set_release(atomic_t *v, int i) { - smp_store_release(&(v)->counter, i); + if (__native_word(atomic_t)) { + smp_store_release(&(v)->counter, i); + } else { + __atomic_release_fence(); + arch_atomic_set(v, i); + } } #define arch_atomic_set_release arch_atomic_set_release #endif @@ -1258,7 +1272,16 @@ arch_atomic_dec_if_positive(atomic_t *v) static __always_inline s64 arch_atomic64_read_acquire(const atomic64_t *v) { - return smp_load_acquire(&(v)->counter); + s64 ret; + + if (__native_word(atomic64_t)) { + ret =3D smp_load_acquire(&(v)->counter); + } else { + ret =3D arch_atomic64_read(v); + __atomic_acquire_fence(); + } + + return ret; } #define arch_atomic64_read_acquire arch_atomic64_read_acquire #endif @@ -1267,7 +1290,12 @@ arch_atomic64_read_acquire(const atomic64_t *v) static __always_inline void arch_atomic64_set_release(atomic64_t *v, s64 i) { - smp_store_release(&(v)->counter, i); + if (__native_word(atomic64_t)) { + smp_store_release(&(v)->counter, i); + } else { + __atomic_release_fence(); + arch_atomic64_set(v, i); + } } #define arch_atomic64_set_release arch_atomic64_set_release #endif @@ -2358,4 +2386,4 @@ arch_atomic64_dec_if_positive(atomic64_t *v) #endif =20 #endif /* _LINUX_ATOMIC_FALLBACK_H */ -// cca554917d7ea73d5e3e7397dd70c484cad9b2c4 +// 8e2cc06bc0d2c0967d2f8424762bd48555ee40ae diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 049cf9421d83..f821b7243361 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -87,6 +87,9 @@ struct coredump_params { loff_t written; loff_t pos; loff_t to_skip; + int vma_count; + size_t vma_data_size; + struct core_vma_metadata *vma_meta; }; =20 /* diff --git a/include/linux/blk-cgroup.h b/include/linux/blk-cgroup.h index b4de2010fba5..bc5c04d711bb 100644 --- a/include/linux/blk-cgroup.h +++ b/include/linux/blk-cgroup.h @@ -24,6 +24,7 @@ #include #include #include +#include =20 /* percpu_counter batch for blkg_[rw]stats, per-cpu drift doesn't matter */ #define BLKG_STAT_CPU_BATCH (INT_MAX / 2) @@ -604,6 +605,21 @@ static inline void blkcg_clear_delay(struct blkcg_gq *= blkg) atomic_dec(&blkg->blkcg->css.cgroup->congestion_count); } =20 +/** + * blk_cgroup_mergeable - Determine whether to allow or disallow merges + * @rq: request to merge into + * @bio: bio to merge + * + * @bio and @rq should belong to the same cgroup and their issue_as_root s= hould + * match. The latter is necessary as we don't want to throttle e.g. a meta= data + * update because it happens to be next to a regular IO. + */ +static inline bool blk_cgroup_mergeable(struct request *rq, struct bio *bi= o) +{ + return rq->bio->bi_blkg =3D=3D bio->bi_blkg && + bio_issue_as_root_blkg(rq->bio) =3D=3D bio_issue_as_root_blkg(bio); +} + void blk_cgroup_bio_start(struct bio *bio); void blkcg_add_delay(struct blkcg_gq *blkg, u64 now, u64 delta); void blkcg_schedule_throttle(struct request_queue *q, bool use_memdelay); @@ -659,6 +675,7 @@ static inline void blkg_put(struct blkcg_gq *blkg) { } static inline bool blkcg_punt_bio_submit(struct bio *bio) { return false; } static inline void blkcg_bio_issue_init(struct bio *bio) { } static inline void blk_cgroup_bio_start(struct bio *bio) { } +static inline bool blk_cgroup_mergeable(struct request *rq, struct bio *bi= o) { return true; } =20 #define blk_queue_for_each_rl(rl, q) \ for ((rl) =3D &(q)->root_rl; (rl); (rl) =3D NULL) diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index fe065c394fff..86c0f85df8bb 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -317,7 +317,8 @@ enum { BIO_TRACE_COMPLETION, /* bio_endio() should trace the final completion * of this bio. */ BIO_CGROUP_ACCT, /* has been accounted to a cgroup */ - BIO_TRACKED, /* set if bio goes through the rq_qos path */ + BIO_QOS_THROTTLED, /* bio went through rq_qos throttle path */ + BIO_QOS_MERGED, /* but went through rq_qos merge path */ BIO_REMAPPED, BIO_ZONE_WRITE_LOCKED, /* Owns a zoned device zone write lock */ BIO_PERCPU_CACHE, /* can participate in per-cpu alloc cache */ diff --git a/include/linux/coredump.h b/include/linux/coredump.h index 78fcd776b185..4b95e46d215f 100644 --- a/include/linux/coredump.h +++ b/include/linux/coredump.h @@ -12,6 +12,8 @@ struct core_vma_metadata { unsigned long start, end; unsigned long flags; unsigned long dump_size; + unsigned long pgoff; + struct file *file; }; =20 extern int core_uses_pid; @@ -29,9 +31,6 @@ extern int dump_emit(struct coredump_params *cprm, const = void *addr, int nr); extern int dump_align(struct coredump_params *cprm, int align); int dump_user_range(struct coredump_params *cprm, unsigned long start, unsigned long len); -int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count, - struct core_vma_metadata **vma_meta, - size_t *vma_data_size_ptr); extern void do_coredump(const kernel_siginfo_t *siginfo); #else static inline void do_coredump(const kernel_siginfo_t *siginfo) {} diff --git a/include/linux/fb.h b/include/linux/fb.h index 02f362c661c8..3d7306c9a706 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -502,6 +502,7 @@ struct fb_info { } *apertures; =20 bool skip_vt_switch; /* no VT switch on suspend/resume required */ + bool forced_out; /* set when being removed by another driver */ }; =20 static inline struct apertures_struct *alloc_apertures(unsigned int max_nu= m) { diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index f0c7b352340a..2e078f40195d 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -335,6 +335,8 @@ LSM_HOOK(int, 0, sctp_bind_connect, struct sock *sk, in= t optname, struct sockaddr *address, int addrlen) LSM_HOOK(void, LSM_RET_VOID, sctp_sk_clone, struct sctp_association *asoc, struct sock *sk, struct sock *newsk) +LSM_HOOK(int, 0, sctp_assoc_established, struct sctp_association *asoc, + struct sk_buff *skb) #endif /* CONFIG_SECURITY_NETWORK */ =20 #ifdef CONFIG_SECURITY_INFINIBAND diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index d45b6f6e27fd..d6823214d5c1 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1050,6 +1050,11 @@ * @asoc pointer to current sctp association structure. * @sk pointer to current sock structure. * @newsk pointer to new sock structure. + * @sctp_assoc_established: + * Passes the @asoc and @chunk->skb of the association COOKIE_ACK packet + * to the security module. + * @asoc pointer to sctp association structure. + * @skb pointer to skbuff of association packet. * * Security hooks for Infiniband * diff --git a/include/linux/mm.h b/include/linux/mm.h index 73210623bda7..1e553c12841e 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1840,20 +1840,6 @@ struct zap_details { struct page *single_page; /* Locked page to be unmapped */ }; =20 -/* - * We set details->zap_mappings when we want to unmap shared but keep priv= ate - * pages. Return true if skip zapping this page, false otherwise. - */ -static inline bool -zap_skip_check_mapping(struct zap_details *details, struct page *page) -{ - if (!details || !page) - return false; - - return details->zap_mapping && - (details->zap_mapping !=3D page_rmapping(page)); -} - struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, pte_t pte); struct page *vm_normal_page_pmd(struct vm_area_struct *vma, unsigned long = addr, diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 5b88cd51fadb..dcf90144d70b 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1240,6 +1240,7 @@ struct nand_secure_region { * @lock: Lock protecting the suspended field. Also used to serialize acce= sses * to the NAND device * @suspended: Set to 1 when the device is suspended, 0 when it's not + * @resume_wq: wait queue to sleep if rawnand is in suspended state. * @cur_cs: Currently selected target. -1 means no target selected, otherw= ise we * should always have cur_cs >=3D 0 && cur_cs < nanddev_ntargets(= ). * NAND Controller drivers should not modify this value, but they= 're @@ -1294,6 +1295,7 @@ struct nand_chip { /* Internals */ struct mutex lock; unsigned int suspended : 1; + wait_queue_head_t resume_wq; int cur_cs; int read_retries; struct nand_secure_region *secure_regions; diff --git a/include/linux/netfilter_netdev.h b/include/linux/netfilter_net= dev.h index e6487a691136..8676316547cc 100644 --- a/include/linux/netfilter_netdev.h +++ b/include/linux/netfilter_netdev.h @@ -99,7 +99,7 @@ static inline struct sk_buff *nf_hook_egress(struct sk_bu= ff *skb, int *rc, return skb; =20 nf_hook_state_init(&state, NF_NETDEV_EGRESS, - NFPROTO_NETDEV, dev, NULL, NULL, + NFPROTO_NETDEV, NULL, dev, NULL, dev_net(dev), NULL); =20 /* nf assumes rcu_read_lock, not just read_lock_bh */ diff --git a/include/linux/nvme.h b/include/linux/nvme.h index 855dd9b3e84b..a662435c9b6f 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -337,6 +337,7 @@ enum { NVME_CTRL_ONCS_TIMESTAMP =3D 1 << 6, NVME_CTRL_VWC_PRESENT =3D 1 << 0, NVME_CTRL_OACS_SEC_SUPP =3D 1 << 0, + NVME_CTRL_OACS_NS_MNGT_SUPP =3D 1 << 3, NVME_CTRL_OACS_DIRECTIVES =3D 1 << 5, NVME_CTRL_OACS_DBBUF_SUPP =3D 1 << 8, NVME_CTRL_LPA_CMD_EFFECTS_LOG =3D 1 << 1, diff --git a/include/linux/pci.h b/include/linux/pci.h index 18a75c8e615c..2d6118937d07 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -656,6 +656,7 @@ struct pci_bus { struct bin_attribute *legacy_io; /* Legacy I/O for this bus */ struct bin_attribute *legacy_mem; /* Legacy mem */ unsigned int is_added:1; + unsigned int unsafe_warn:1; /* warned about RW1C config write */ }; =20 #define to_pci_bus(n) container_of(n, struct pci_bus, dev) diff --git a/include/linux/pstore.h b/include/linux/pstore.h index eb93a54cff31..e97a8188f0fd 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include =20 @@ -87,7 +87,7 @@ struct pstore_record { * @owner: module which is responsible for this backend driver * @name: name of the backend driver * - * @buf_lock: semaphore to serialize access to @buf + * @buf_lock: spinlock to serialize access to @buf * @buf: preallocated crash dump buffer * @bufsize: size of @buf available for crash dump bytes (must match * smallest number of bytes available for writing to a @@ -178,7 +178,7 @@ struct pstore_info { struct module *owner; const char *name; =20 - struct semaphore buf_lock; + spinlock_t buf_lock; char *buf; size_t bufsize; =20 diff --git a/include/linux/randomize_kstack.h b/include/linux/randomize_kst= ack.h index bebc911161b6..d373f1bcbf7c 100644 --- a/include/linux/randomize_kstack.h +++ b/include/linux/randomize_kstack.h @@ -16,8 +16,20 @@ DECLARE_PER_CPU(u32, kstack_offset); * alignment. Also, since this use is being explicitly masked to a max of * 10 bits, stack-clash style attacks are unlikely. For more details see * "VLAs" in Documentation/process/deprecated.rst + * + * The normal __builtin_alloca() is initialized with INIT_STACK_ALL (curre= ntly + * only with Clang and not GCC). Initializing the unused area on each sysc= all + * entry is expensive, and generating an implicit call to memset() may als= o be + * problematic (such as in noinstr functions). Therefore, if the compiler + * supports it (which it should if it initializes allocas), always use the + * "uninitialized" variant of the builtin. */ -void *__builtin_alloca(size_t size); +#if __has_builtin(__builtin_alloca_uninitialized) +#define __kstack_alloca __builtin_alloca_uninitialized +#else +#define __kstack_alloca __builtin_alloca +#endif + /* * Use, at most, 10 bits of entropy. We explicitly cap this to keep the * "VLA" from being unbounded (see above). 10 bits leaves enough room for @@ -36,7 +48,7 @@ void *__builtin_alloca(size_t size); if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT, \ &randomize_kstack_offset)) { \ u32 offset =3D raw_cpu_read(kstack_offset); \ - u8 *ptr =3D __builtin_alloca(KSTACK_OFFSET_MAX(offset)); \ + u8 *ptr =3D __kstack_alloca(KSTACK_OFFSET_MAX(offset)); \ /* Keep allocation even after "ptr" loses scope. */ \ asm volatile("" :: "r"(ptr) : "memory"); \ } \ diff --git a/include/linux/sched.h b/include/linux/sched.h index ee5ed8821963..3375bb533f9d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1622,6 +1622,14 @@ static inline unsigned int task_state_index(struct t= ask_struct *tsk) if (tsk_state =3D=3D TASK_IDLE) state =3D TASK_REPORT_IDLE; =20 + /* + * We're lying here, but rather than expose a completely new task state + * to userspace, we can make this appear as if the task has gone through + * a regular rt_mutex_lock() call. + */ + if (tsk_state =3D=3D TASK_RTLOCK_WAIT) + state =3D TASK_UNINTERRUPTIBLE; + return fls(state); } =20 diff --git a/include/linux/security.h b/include/linux/security.h index bbf44a466832..bd059e7b4766 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1430,6 +1430,8 @@ int security_sctp_bind_connect(struct sock *sk, int o= ptname, struct sockaddr *address, int addrlen); void security_sctp_sk_clone(struct sctp_association *asoc, struct sock *sk, struct sock *newsk); +int security_sctp_assoc_established(struct sctp_association *asoc, + struct sk_buff *skb); =20 #else /* CONFIG_SECURITY_NETWORK */ static inline int security_unix_stream_connect(struct sock *sock, @@ -1649,6 +1651,12 @@ static inline void security_sctp_sk_clone(struct sct= p_association *asoc, struct sock *newsk) { } + +static inline int security_sctp_assoc_established(struct sctp_association = *asoc, + struct sk_buff *skb) +{ + return 0; +} #endif /* CONFIG_SECURITY_NETWORK */ =20 #ifdef CONFIG_SECURITY_INFINIBAND diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index c58cc142d23f..8c32935e1059 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -458,6 +458,8 @@ extern void uart_handle_cts_change(struct uart_port *up= ort, extern void uart_insert_char(struct uart_port *port, unsigned int status, unsigned int overrun, unsigned int ch, unsigned int flag); =20 +void uart_xchar_out(struct uart_port *uport, int offset); + #ifdef CONFIG_MAGIC_SYSRQ_SERIAL #define SYSRQ_TIMEOUT (HZ * 5) =20 diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 60ab0c2fe567..5078e1a505c3 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1446,6 +1446,11 @@ static inline unsigned int skb_end_offset(const stru= ct sk_buff *skb) { return skb->end; } + +static inline void skb_set_end_offset(struct sk_buff *skb, unsigned int of= fset) +{ + skb->end =3D offset; +} #else static inline unsigned char *skb_end_pointer(const struct sk_buff *skb) { @@ -1456,6 +1461,11 @@ static inline unsigned int skb_end_offset(const stru= ct sk_buff *skb) { return skb->end - skb->head; } + +static inline void skb_set_end_offset(struct sk_buff *skb, unsigned int of= fset) +{ + skb->end =3D skb->head + offset; +} #endif =20 /* Internal */ @@ -1695,19 +1705,19 @@ static inline int skb_unclone(struct sk_buff *skb, = gfp_t pri) return 0; } =20 -/* This variant of skb_unclone() makes sure skb->truesize is not changed */ +/* This variant of skb_unclone() makes sure skb->truesize + * and skb_end_offset() are not changed, whenever a new skb->head is neede= d. + * + * Indeed there is no guarantee that ksize(kmalloc(X)) =3D=3D ksize(kmallo= c(X)) + * when various debugging features are in place. + */ +int __skb_unclone_keeptruesize(struct sk_buff *skb, gfp_t pri); static inline int skb_unclone_keeptruesize(struct sk_buff *skb, gfp_t pri) { might_sleep_if(gfpflags_allow_blocking(pri)); =20 - if (skb_cloned(skb)) { - unsigned int save =3D skb->truesize; - int res; - - res =3D pskb_expand_head(skb, 0, 0, pri); - skb->truesize =3D save; - return res; - } + if (skb_cloned(skb)) + return __skb_unclone_keeptruesize(skb, pri); return 0; } =20 diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h index 18a717fe62eb..7f32dd59e751 100644 --- a/include/linux/skmsg.h +++ b/include/linux/skmsg.h @@ -310,21 +310,16 @@ static inline void sock_drop(struct sock *sk, struct = sk_buff *skb) kfree_skb(skb); } =20 -static inline void drop_sk_msg(struct sk_psock *psock, struct sk_msg *msg) -{ - if (msg->skb) - sock_drop(psock->sk, msg->skb); - kfree(msg); -} - static inline void sk_psock_queue_msg(struct sk_psock *psock, struct sk_msg *msg) { spin_lock_bh(&psock->ingress_lock); if (sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED)) list_add_tail(&msg->list, &psock->ingress_msg); - else - drop_sk_msg(psock, msg); + else { + sk_msg_free(psock->sk, msg); + kfree(msg); + } spin_unlock_bh(&psock->ingress_lock); } =20 diff --git a/include/linux/soc/ti/ti_sci_protocol.h b/include/linux/soc/ti/= ti_sci_protocol.h index 0aad7009b50e..bd0d11af76c5 100644 --- a/include/linux/soc/ti/ti_sci_protocol.h +++ b/include/linux/soc/ti/ti_sci_protocol.h @@ -645,7 +645,7 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle = *handle, =20 static inline struct ti_sci_resource * devm_ti_sci_get_resource(const struct ti_sci_handle *handle, struct device= *dev, - u32 dev_id, u32 sub_type); + u32 dev_id, u32 sub_type) { return ERR_PTR(-EINVAL); } diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index b519609af1d0..4417f667c757 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -731,6 +731,8 @@ xdr_stream_decode_uint32_array(struct xdr_stream *xdr, =20 if (unlikely(xdr_stream_decode_u32(xdr, &len) < 0)) return -EBADMSG; + if (len > SIZE_MAX / sizeof(*p)) + return -EBADMSG; p =3D xdr_inline_decode(xdr, len * sizeof(*p)); if (unlikely(!p)) return -EBADMSG; diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 955ea4d7af0b..eef5e87c03b4 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -139,6 +139,9 @@ struct rpc_xprt_ops { void (*rpcbind)(struct rpc_task *task); void (*set_port)(struct rpc_xprt *xprt, unsigned short port); void (*connect)(struct rpc_xprt *xprt, struct rpc_task *task); + int (*get_srcaddr)(struct rpc_xprt *xprt, char *buf, + size_t buflen); + unsigned short (*get_srcport)(struct rpc_xprt *xprt); int (*buf_alloc)(struct rpc_task *task); void (*buf_free)(struct rpc_task *task); void (*prepare_request)(struct rpc_rqst *req); diff --git a/include/linux/sunrpc/xprtsock.h b/include/linux/sunrpc/xprtsoc= k.h index 8c2a712cb242..fed813ffe7db 100644 --- a/include/linux/sunrpc/xprtsock.h +++ b/include/linux/sunrpc/xprtsock.h @@ -10,7 +10,6 @@ =20 int init_socket_xprt(void); void cleanup_socket_xprt(void); -unsigned short get_srcport(struct rpc_xprt *); =20 #define RPC_MIN_RESVPORT (1U) #define RPC_MAX_RESVPORT (65535U) @@ -89,5 +88,6 @@ struct sock_xprt { #define XPRT_SOCK_WAKE_WRITE (5) #define XPRT_SOCK_WAKE_PENDING (6) #define XPRT_SOCK_WAKE_DISCONNECT (7) +#define XPRT_SOCK_CONNECT_SENT (8) =20 #endif /* _LINUX_SUNRPC_XPRTSOCK_H */ diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netf= ilter/nf_conntrack_helper.h index 37f0fbefb060..9939c366f720 100644 --- a/include/net/netfilter/nf_conntrack_helper.h +++ b/include/net/netfilter/nf_conntrack_helper.h @@ -177,4 +177,5 @@ void nf_nat_helper_unregister(struct nf_conntrack_nat_h= elper *nat); int nf_nat_helper_try_module_get(const char *name, u16 l3num, u8 protonum); void nf_nat_helper_put(struct nf_conntrack_helper *helper); +void nf_ct_set_auto_assign_helper_warned(struct net *net); #endif /*_NF_CONNTRACK_HELPER_H*/ diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/= nf_flow_table.h index a3647fadf1cc..9f927c44087d 100644 --- a/include/net/netfilter/nf_flow_table.h +++ b/include/net/netfilter/nf_flow_table.h @@ -10,6 +10,8 @@ #include #include #include +#include +#include =20 struct nf_flowtable; struct nf_flow_rule; @@ -313,4 +315,20 @@ int nf_flow_rule_route_ipv6(struct net *net, const str= uct flow_offload *flow, int nf_flow_table_offload_init(void); void nf_flow_table_offload_exit(void); =20 +static inline __be16 nf_flow_pppoe_proto(const struct sk_buff *skb) +{ + __be16 proto; + + proto =3D *((__be16 *)(skb_mac_header(skb) + ETH_HLEN + + sizeof(struct pppoe_hdr))); + switch (proto) { + case htons(PPP_IP): + return htons(ETH_P_IP); + case htons(PPP_IPV6): + return htons(ETH_P_IPV6); + } + + return 0; +} + #endif /* _NF_FLOW_TABLE_H */ diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index d1c6fc83b1e3..5a54bb7fc656 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -206,6 +206,7 @@ struct scsi_device { unsigned rpm_autosuspend:1; /* Enable runtime autosuspend at device * creation time */ unsigned ignore_media_change:1; /* Ignore MEDIA CHANGE on resume */ + unsigned silence_suspend:1; /* Do not print runtime PM related messages */ =20 unsigned int queue_stopped; /* request queue is quiesced */ bool offline_already; /* Device offline message logged */ diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 2018b7512d3d..e08bf475d02d 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -399,6 +399,7 @@ struct snd_pcm_runtime { struct fasync_struct *fasync; bool stop_operating; /* sync_stop will be called */ struct mutex buffer_mutex; /* protect for buffer changes */ + atomic_t buffer_accessing; /* >0: in r/w operation, <0: blocked */ =20 /* -- private section -- */ void *private_data; diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h index 0ea36b2b0662..61a64d1b2bb6 100644 --- a/include/trace/events/ext4.h +++ b/include/trace/events/ext4.h @@ -95,6 +95,17 @@ TRACE_DEFINE_ENUM(ES_REFERENCED_B); { FALLOC_FL_COLLAPSE_RANGE, "COLLAPSE_RANGE"}, \ { FALLOC_FL_ZERO_RANGE, "ZERO_RANGE"}) =20 +TRACE_DEFINE_ENUM(EXT4_FC_REASON_XATTR); +TRACE_DEFINE_ENUM(EXT4_FC_REASON_CROSS_RENAME); +TRACE_DEFINE_ENUM(EXT4_FC_REASON_JOURNAL_FLAG_CHANGE); +TRACE_DEFINE_ENUM(EXT4_FC_REASON_NOMEM); +TRACE_DEFINE_ENUM(EXT4_FC_REASON_SWAP_BOOT); +TRACE_DEFINE_ENUM(EXT4_FC_REASON_RESIZE); +TRACE_DEFINE_ENUM(EXT4_FC_REASON_RENAME_DIR); +TRACE_DEFINE_ENUM(EXT4_FC_REASON_FALLOC_RANGE); +TRACE_DEFINE_ENUM(EXT4_FC_REASON_INODE_JOURNAL_DATA); +TRACE_DEFINE_ENUM(EXT4_FC_REASON_MAX); + #define show_fc_reason(reason) \ __print_symbolic(reason, \ { EXT4_FC_REASON_XATTR, "XATTR"}, \ @@ -2723,41 +2734,50 @@ TRACE_EVENT(ext4_fc_commit_stop, =20 #define FC_REASON_NAME_STAT(reason) \ show_fc_reason(reason), \ - __entry->sbi->s_fc_stats.fc_ineligible_reason_count[reason] + __entry->fc_ineligible_rc[reason] =20 TRACE_EVENT(ext4_fc_stats, - TP_PROTO(struct super_block *sb), - - TP_ARGS(sb), + TP_PROTO(struct super_block *sb), =20 - TP_STRUCT__entry( - __field(dev_t, dev) - __field(struct ext4_sb_info *, sbi) - __field(int, count) - ), + TP_ARGS(sb), =20 - TP_fast_assign( - __entry->dev =3D sb->s_dev; - __entry->sbi =3D EXT4_SB(sb); - ), + TP_STRUCT__entry( + __field(dev_t, dev) + __array(unsigned int, fc_ineligible_rc, EXT4_FC_REASON_MAX) + __field(unsigned long, fc_commits) + __field(unsigned long, fc_ineligible_commits) + __field(unsigned long, fc_numblks) + ), =20 - TP_printk("dev %d:%d fc ineligible reasons:\n" - "%s:%d, %s:%d, %s:%d, %s:%d, %s:%d, %s:%d, %s:%d, %s:%d, %s:%d; " - "num_commits:%ld, ineligible: %ld, numblks: %ld", - MAJOR(__entry->dev), MINOR(__entry->dev), - FC_REASON_NAME_STAT(EXT4_FC_REASON_XATTR), - FC_REASON_NAME_STAT(EXT4_FC_REASON_CROSS_RENAME), - FC_REASON_NAME_STAT(EXT4_FC_REASON_JOURNAL_FLAG_CHANGE), - FC_REASON_NAME_STAT(EXT4_FC_REASON_NOMEM), - FC_REASON_NAME_STAT(EXT4_FC_REASON_SWAP_BOOT), - FC_REASON_NAME_STAT(EXT4_FC_REASON_RESIZE), - FC_REASON_NAME_STAT(EXT4_FC_REASON_RENAME_DIR), - FC_REASON_NAME_STAT(EXT4_FC_REASON_FALLOC_RANGE), - FC_REASON_NAME_STAT(EXT4_FC_REASON_INODE_JOURNAL_DATA), - __entry->sbi->s_fc_stats.fc_num_commits, - __entry->sbi->s_fc_stats.fc_ineligible_commits, - __entry->sbi->s_fc_stats.fc_numblks) + TP_fast_assign( + int i; =20 + __entry->dev =3D sb->s_dev; + for (i =3D 0; i < EXT4_FC_REASON_MAX; i++) { + __entry->fc_ineligible_rc[i] =3D + EXT4_SB(sb)->s_fc_stats.fc_ineligible_reason_count[i]; + } + __entry->fc_commits =3D EXT4_SB(sb)->s_fc_stats.fc_num_commits; + __entry->fc_ineligible_commits =3D + EXT4_SB(sb)->s_fc_stats.fc_ineligible_commits; + __entry->fc_numblks =3D EXT4_SB(sb)->s_fc_stats.fc_numblks; + ), + + TP_printk("dev %d,%d fc ineligible reasons:\n" + "%s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u " + "num_commits:%lu, ineligible: %lu, numblks: %lu", + MAJOR(__entry->dev), MINOR(__entry->dev), + FC_REASON_NAME_STAT(EXT4_FC_REASON_XATTR), + FC_REASON_NAME_STAT(EXT4_FC_REASON_CROSS_RENAME), + FC_REASON_NAME_STAT(EXT4_FC_REASON_JOURNAL_FLAG_CHANGE), + FC_REASON_NAME_STAT(EXT4_FC_REASON_NOMEM), + FC_REASON_NAME_STAT(EXT4_FC_REASON_SWAP_BOOT), + FC_REASON_NAME_STAT(EXT4_FC_REASON_RESIZE), + FC_REASON_NAME_STAT(EXT4_FC_REASON_RENAME_DIR), + FC_REASON_NAME_STAT(EXT4_FC_REASON_FALLOC_RANGE), + FC_REASON_NAME_STAT(EXT4_FC_REASON_INODE_JOURNAL_DATA), + __entry->fc_commits, __entry->fc_ineligible_commits, + __entry->fc_numblks) ); =20 #define DEFINE_TRACE_DENTRY_EVENT(__type) \ diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h index e70c90116eda..4a3ab0ed6e06 100644 --- a/include/trace/events/rxrpc.h +++ b/include/trace/events/rxrpc.h @@ -83,12 +83,15 @@ enum rxrpc_call_trace { rxrpc_call_error, rxrpc_call_got, rxrpc_call_got_kernel, + rxrpc_call_got_timer, rxrpc_call_got_userid, rxrpc_call_new_client, rxrpc_call_new_service, rxrpc_call_put, rxrpc_call_put_kernel, rxrpc_call_put_noqueue, + rxrpc_call_put_notimer, + rxrpc_call_put_timer, rxrpc_call_put_userid, rxrpc_call_queued, rxrpc_call_queued_ref, @@ -278,12 +281,15 @@ enum rxrpc_tx_point { EM(rxrpc_call_error, "*E*") \ EM(rxrpc_call_got, "GOT") \ EM(rxrpc_call_got_kernel, "Gke") \ + EM(rxrpc_call_got_timer, "GTM") \ EM(rxrpc_call_got_userid, "Gus") \ EM(rxrpc_call_new_client, "NWc") \ EM(rxrpc_call_new_service, "NWs") \ EM(rxrpc_call_put, "PUT") \ EM(rxrpc_call_put_kernel, "Pke") \ - EM(rxrpc_call_put_noqueue, "PNQ") \ + EM(rxrpc_call_put_noqueue, "PnQ") \ + EM(rxrpc_call_put_notimer, "PnT") \ + EM(rxrpc_call_put_timer, "PTM") \ EM(rxrpc_call_put_userid, "Pus") \ EM(rxrpc_call_queued, "QUE") \ EM(rxrpc_call_queued_ref, "QUR") \ diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index b12cfceddb6e..2b3c3f83076c 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -2284,8 +2284,8 @@ union bpf_attr { * Return * The return value depends on the result of the test, and can be: * - * * 0, if current task belongs to the cgroup2. - * * 1, if current task does not belong to the cgroup2. + * * 1, if current task belongs to the cgroup2. + * * 0, if current task does not belong to the cgroup2. * * A negative error code, if an error occurred. * * long bpf_skb_change_tail(struct sk_buff *skb, u32 len, u64 flags) @@ -2973,8 +2973,8 @@ union bpf_attr { * * # sysctl kernel.perf_event_max_stack=3D * Return - * A non-negative value equal to or less than *size* on success, - * or a negative error in case of failure. + * The non-negative copied *buf* length equal to or less than + * *size* on success, or a negative error in case of failure. * * long bpf_skb_load_bytes_relative(const void *skb, u32 offset, void *to,= u32 len, u32 start_header) * Description @@ -4277,8 +4277,8 @@ union bpf_attr { * * # sysctl kernel.perf_event_max_stack=3D * Return - * A non-negative value equal to or less than *size* on success, - * or a negative error in case of failure. + * The non-negative copied *buf* length equal to or less than + * *size* on success, or a negative error in case of failure. * * long bpf_load_hdr_opt(struct bpf_sock_ops *skops, void *searchby_res, u= 32 len, u64 flags) * Description diff --git a/include/uapi/linux/loop.h b/include/uapi/linux/loop.h index 24a1c45bd1ae..98e60801195e 100644 --- a/include/uapi/linux/loop.h +++ b/include/uapi/linux/loop.h @@ -45,7 +45,7 @@ struct loop_info { unsigned long lo_inode; /* ioctl r/o */ __kernel_old_dev_t lo_rdevice; /* ioctl r/o */ int lo_offset; - int lo_encrypt_type; + int lo_encrypt_type; /* obsolete, ignored */ int lo_encrypt_key_size; /* ioctl w/o */ int lo_flags; char lo_name[LO_NAME_SIZE]; @@ -61,7 +61,7 @@ struct loop_info64 { __u64 lo_offset; __u64 lo_sizelimit;/* bytes, 0 =3D=3D max available */ __u32 lo_number; /* ioctl r/o */ - __u32 lo_encrypt_type; + __u32 lo_encrypt_type; /* obsolete, ignored */ __u32 lo_encrypt_key_size; /* ioctl w/o */ __u32 lo_flags; __u8 lo_file_name[LO_NAME_SIZE]; diff --git a/include/uapi/linux/omap3isp.h b/include/uapi/linux/omap3isp.h index 87b55755f4ff..d9db7ad43890 100644 --- a/include/uapi/linux/omap3isp.h +++ b/include/uapi/linux/omap3isp.h @@ -162,6 +162,7 @@ struct omap3isp_h3a_aewb_config { * struct omap3isp_stat_data - Statistic data sent to or received from user * @ts: Timestamp of returned framestats. * @buf: Pointer to pass to user. + * @buf_size: Size of buffer. * @frame_number: Frame number of requested stats. * @cur_frame: Current frame number being processed. * @config_counter: Number of the configuration associated with the data. @@ -176,10 +177,12 @@ struct omap3isp_stat_data { struct timeval ts; #endif void __user *buf; - __u32 buf_size; - __u16 frame_number; - __u16 cur_frame; - __u16 config_counter; + __struct_group(/* no tag */, frame, /* no attrs */, + __u32 buf_size; + __u16 frame_number; + __u16 cur_frame; + __u16 config_counter; + ); }; =20 #ifdef __KERNEL__ @@ -189,10 +192,12 @@ struct omap3isp_stat_data_time32 { __s32 tv_usec; } ts; __u32 buf; - __u32 buf_size; - __u16 frame_number; - __u16 cur_frame; - __u16 config_counter; + __struct_group(/* no tag */, frame, /* no attrs */, + __u32 buf_size; + __u16 frame_number; + __u16 cur_frame; + __u16 config_counter; + ); }; #endif =20 diff --git a/include/uapi/linux/rfkill.h b/include/uapi/linux/rfkill.h index 9b77cfc42efa..283c5a7b3f2c 100644 --- a/include/uapi/linux/rfkill.h +++ b/include/uapi/linux/rfkill.h @@ -159,8 +159,16 @@ struct rfkill_event_ext { * old behaviour for all userspace, unless it explicitly opts in to the * rules outlined here by using the new &struct rfkill_event_ext. * - * Userspace using &struct rfkill_event_ext must adhere to the following - * rules + * Additionally, some other userspace (bluez, g-s-d) was reading with a + * large size but as streaming reads rather than message-based, or with + * too strict checks for the returned size. So eventually, we completely + * reverted this, and extended messages need to be opted in to by using + * an ioctl: + * + * ioctl(fd, RFKILL_IOCTL_MAX_SIZE, sizeof(struct rfkill_event_ext)); + * + * Userspace using &struct rfkill_event_ext and the ioctl must adhere to + * the following rules: * * 1. accept short writes, optionally using them to detect that it's * running on an older kernel; @@ -175,6 +183,8 @@ struct rfkill_event_ext { #define RFKILL_IOC_MAGIC 'R' #define RFKILL_IOC_NOINPUT 1 #define RFKILL_IOCTL_NOINPUT _IO(RFKILL_IOC_MAGIC, RFKILL_IOC_NOINPUT) +#define RFKILL_IOC_MAX_SIZE 2 +#define RFKILL_IOCTL_MAX_SIZE _IOW(RFKILL_IOC_MAGIC, RFKILL_IOC_EXT_SIZE, = __u32) =20 /* and that's all userspace gets */ =20 diff --git a/include/uapi/linux/rseq.h b/include/uapi/linux/rseq.h index 9a402fdb60e9..77ee207623a9 100644 --- a/include/uapi/linux/rseq.h +++ b/include/uapi/linux/rseq.h @@ -105,23 +105,11 @@ struct rseq { * Read and set by the kernel. Set by user-space with single-copy * atomicity semantics. This field should only be updated by the * thread which registered this data structure. Aligned on 64-bit. + * + * 32-bit architectures should update the low order bits of the + * rseq_cs field, leaving the high order bits initialized to 0. */ - union { - __u64 ptr64; -#ifdef __LP64__ - __u64 ptr; -#else - struct { -#if (defined(__BYTE_ORDER) && (__BYTE_ORDER =3D=3D __BIG_ENDIAN)) || defin= ed(__BIG_ENDIAN) - __u32 padding; /* Initialized to zero. */ - __u32 ptr32; -#else /* LITTLE */ - __u32 ptr32; - __u32 padding; /* Initialized to zero. */ -#endif /* ENDIAN */ - } ptr; -#endif - } rseq_cs; + __u64 rseq_cs; =20 /* * Restartable sequences flags field. diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_c= ore.h index c4042dcfdc0c..8885e69178bd 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -68,6 +68,9 @@ /* NVIDIA Tegra Combined UART */ #define PORT_TEGRA_TCU 41 =20 +/* ASPEED AST2x00 virtual UART */ +#define PORT_ASPEED_VUART 42 + /* Intel EG20 */ #define PORT_PCH_8LINE 44 #define PORT_PCH_2LINE 45 diff --git a/kernel/audit.h b/kernel/audit.h index c4498090a5bd..58b66543b4d5 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -201,6 +201,10 @@ struct audit_context { struct { char *name; } module; + struct { + struct audit_ntp_data ntp_data; + struct timespec64 tk_injoffset; + } time; }; int fds[2]; struct audit_proctitle proctitle; diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 2dc94a0e3447..321904af2311 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -1331,6 +1331,53 @@ static void audit_log_fcaps(struct audit_buffer *ab,= struct audit_names *name) from_kuid(&init_user_ns, name->fcap.rootid)); } =20 +static void audit_log_time(struct audit_context *context, struct audit_buf= fer **ab) +{ + const struct audit_ntp_data *ntp =3D &context->time.ntp_data; + const struct timespec64 *tk =3D &context->time.tk_injoffset; + static const char * const ntp_name[] =3D { + "offset", + "freq", + "status", + "tai", + "tick", + "adjust", + }; + int type; + + if (context->type =3D=3D AUDIT_TIME_ADJNTPVAL) { + for (type =3D 0; type < AUDIT_NTP_NVALS; type++) { + if (ntp->vals[type].newval !=3D ntp->vals[type].oldval) { + if (!*ab) { + *ab =3D audit_log_start(context, + GFP_KERNEL, + AUDIT_TIME_ADJNTPVAL); + if (!*ab) + return; + } + audit_log_format(*ab, "op=3D%s old=3D%lli new=3D%lli", + ntp_name[type], + ntp->vals[type].oldval, + ntp->vals[type].newval); + audit_log_end(*ab); + *ab =3D NULL; + } + } + } + if (tk->tv_sec !=3D 0 || tk->tv_nsec !=3D 0) { + if (!*ab) { + *ab =3D audit_log_start(context, GFP_KERNEL, + AUDIT_TIME_INJOFFSET); + if (!*ab) + return; + } + audit_log_format(*ab, "sec=3D%lli nsec=3D%li", + (long long)tk->tv_sec, tk->tv_nsec); + audit_log_end(*ab); + *ab =3D NULL; + } +} + static void show_special(struct audit_context *context, int *call_panic) { struct audit_buffer *ab; @@ -1445,6 +1492,11 @@ static void show_special(struct audit_context *conte= xt, int *call_panic) audit_log_format(ab, "(null)"); =20 break; + case AUDIT_TIME_ADJNTPVAL: + case AUDIT_TIME_INJOFFSET: + /* this call deviates from the rest, eating the buffer */ + audit_log_time(context, &ab); + break; } audit_log_end(ab); } @@ -2840,31 +2892,26 @@ void __audit_fanotify(unsigned int response) =20 void __audit_tk_injoffset(struct timespec64 offset) { - audit_log(audit_context(), GFP_KERNEL, AUDIT_TIME_INJOFFSET, - "sec=3D%lli nsec=3D%li", - (long long)offset.tv_sec, offset.tv_nsec); -} - -static void audit_log_ntp_val(const struct audit_ntp_data *ad, - const char *op, enum audit_ntp_type type) -{ - const struct audit_ntp_val *val =3D &ad->vals[type]; - - if (val->newval =3D=3D val->oldval) - return; + struct audit_context *context =3D audit_context(); =20 - audit_log(audit_context(), GFP_KERNEL, AUDIT_TIME_ADJNTPVAL, - "op=3D%s old=3D%lli new=3D%lli", op, val->oldval, val->newval); + /* only set type if not already set by NTP */ + if (!context->type) + context->type =3D AUDIT_TIME_INJOFFSET; + memcpy(&context->time.tk_injoffset, &offset, sizeof(offset)); } =20 void __audit_ntp_log(const struct audit_ntp_data *ad) { - audit_log_ntp_val(ad, "offset", AUDIT_NTP_OFFSET); - audit_log_ntp_val(ad, "freq", AUDIT_NTP_FREQ); - audit_log_ntp_val(ad, "status", AUDIT_NTP_STATUS); - audit_log_ntp_val(ad, "tai", AUDIT_NTP_TAI); - audit_log_ntp_val(ad, "tick", AUDIT_NTP_TICK); - audit_log_ntp_val(ad, "adjust", AUDIT_NTP_ADJUST); + struct audit_context *context =3D audit_context(); + int type; + + for (type =3D 0; type < AUDIT_NTP_NVALS; type++) + if (ad->vals[type].newval !=3D ad->vals[type].oldval) { + /* unconditionally set type, overwriting TK */ + context->type =3D AUDIT_TIME_ADJNTPVAL; + memcpy(&context->time.ntp_data, ad, sizeof(*ad)); + break; + } } =20 void __audit_log_nfcfg(const char *name, u8 af, unsigned int nentries, diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index c9da250fee38..ebbb2f4d3b9c 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -401,6 +401,9 @@ static struct btf_type btf_void; static int btf_resolve(struct btf_verifier_env *env, const struct btf_type *t, u32 type_id); =20 +static int btf_func_check(struct btf_verifier_env *env, + const struct btf_type *t); + static bool btf_type_is_modifier(const struct btf_type *t) { /* Some of them is not strictly a C modifier @@ -576,6 +579,7 @@ static bool btf_type_needs_resolve(const struct btf_typ= e *t) btf_type_is_struct(t) || btf_type_is_array(t) || btf_type_is_var(t) || + btf_type_is_func(t) || btf_type_is_decl_tag(t) || btf_type_is_datasec(t); } @@ -3521,9 +3525,24 @@ static s32 btf_func_check_meta(struct btf_verifier_e= nv *env, return 0; } =20 +static int btf_func_resolve(struct btf_verifier_env *env, + const struct resolve_vertex *v) +{ + const struct btf_type *t =3D v->t; + u32 next_type_id =3D t->type; + int err; + + err =3D btf_func_check(env, t); + if (err) + return err; + + env_stack_pop_resolved(env, next_type_id, 0); + return 0; +} + static struct btf_kind_operations func_ops =3D { .check_meta =3D btf_func_check_meta, - .resolve =3D btf_df_resolve, + .resolve =3D btf_func_resolve, .check_member =3D btf_df_check_member, .check_kflag_member =3D btf_df_check_kflag_member, .log_details =3D btf_ref_type_log, @@ -4143,7 +4162,7 @@ static bool btf_resolve_valid(struct btf_verifier_env= *env, return !btf_resolved_type_id(btf, type_id) && !btf_resolved_type_size(btf, type_id); =20 - if (btf_type_is_decl_tag(t)) + if (btf_type_is_decl_tag(t) || btf_type_is_func(t)) return btf_resolved_type_id(btf, type_id) && !btf_resolved_type_size(btf, type_id); =20 @@ -4233,12 +4252,6 @@ static int btf_check_all_types(struct btf_verifier_e= nv *env) if (err) return err; } - - if (btf_type_is_func(t)) { - err =3D btf_func_check(env, t); - if (err) - return err; - } } =20 return 0; @@ -6189,12 +6202,17 @@ bool btf_id_set_contains(const struct btf_id_set *s= et, u32 id) return bsearch(&id, set->ids, set->cnt, sizeof(u32), btf_id_cmp_func) != =3D NULL; } =20 +enum { + BTF_MODULE_F_LIVE =3D (1 << 0), +}; + #ifdef CONFIG_DEBUG_INFO_BTF_MODULES struct btf_module { struct list_head list; struct module *module; struct btf *btf; struct bin_attribute *sysfs_attr; + int flags; }; =20 static LIST_HEAD(btf_modules); @@ -6220,7 +6238,8 @@ static int btf_module_notify(struct notifier_block *n= b, unsigned long op, int err =3D 0; =20 if (mod->btf_data_size =3D=3D 0 || - (op !=3D MODULE_STATE_COMING && op !=3D MODULE_STATE_GOING)) + (op !=3D MODULE_STATE_COMING && op !=3D MODULE_STATE_LIVE && + op !=3D MODULE_STATE_GOING)) goto out; =20 switch (op) { @@ -6277,6 +6296,17 @@ static int btf_module_notify(struct notifier_block *= nb, unsigned long op, btf_mod->sysfs_attr =3D attr; } =20 + break; + case MODULE_STATE_LIVE: + mutex_lock(&btf_module_mutex); + list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) { + if (btf_mod->module !=3D module) + continue; + + btf_mod->flags |=3D BTF_MODULE_F_LIVE; + break; + } + mutex_unlock(&btf_module_mutex); break; case MODULE_STATE_GOING: mutex_lock(&btf_module_mutex); @@ -6323,7 +6353,12 @@ struct module *btf_try_get_module(const struct btf *= btf) if (btf_mod->btf !=3D btf) continue; =20 - if (try_module_get(btf_mod->module)) + /* We must only consider module whose __init routine has + * finished, hence we must check for BTF_MODULE_F_LIVE flag, + * which is set from the notifier callback for + * MODULE_STATE_LIVE. + */ + if ((btf_mod->flags & BTF_MODULE_F_LIVE) && try_module_get(btf_mod->modu= le)) res =3D btf_mod->module; =20 break; diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index 0dcaed4d3f4c..fc0f77f91224 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -219,7 +219,7 @@ static void stack_map_get_build_id_offset(struct bpf_st= ack_build_id *id_offs, } =20 static struct perf_callchain_entry * -get_callchain_entry_for_task(struct task_struct *task, u32 init_nr) +get_callchain_entry_for_task(struct task_struct *task, u32 max_depth) { #ifdef CONFIG_STACKTRACE struct perf_callchain_entry *entry; @@ -230,9 +230,8 @@ get_callchain_entry_for_task(struct task_struct *task, = u32 init_nr) if (!entry) return NULL; =20 - entry->nr =3D init_nr + - stack_trace_save_tsk(task, (unsigned long *)(entry->ip + init_nr), - sysctl_perf_event_max_stack - init_nr, 0); + entry->nr =3D stack_trace_save_tsk(task, (unsigned long *)entry->ip, + max_depth, 0); =20 /* stack_trace_save_tsk() works on unsigned long array, while * perf_callchain_entry uses u64 array. For 32-bit systems, it is @@ -244,7 +243,7 @@ get_callchain_entry_for_task(struct task_struct *task, = u32 init_nr) int i; =20 /* copy data from the end to avoid using extra buffer */ - for (i =3D entry->nr - 1; i >=3D (int)init_nr; i--) + for (i =3D entry->nr - 1; i >=3D 0; i--) to[i] =3D (u64)(from[i]); } =20 @@ -261,27 +260,19 @@ static long __bpf_get_stackid(struct bpf_map *map, { struct bpf_stack_map *smap =3D container_of(map, struct bpf_stack_map, ma= p); struct stack_map_bucket *bucket, *new_bucket, *old_bucket; - u32 max_depth =3D map->value_size / stack_map_data_size(map); - /* stack_map_alloc() checks that max_depth <=3D sysctl_perf_event_max_sta= ck */ - u32 init_nr =3D sysctl_perf_event_max_stack - max_depth; u32 skip =3D flags & BPF_F_SKIP_FIELD_MASK; u32 hash, id, trace_nr, trace_len; bool user =3D flags & BPF_F_USER_STACK; u64 *ips; bool hash_matches; =20 - /* get_perf_callchain() guarantees that trace->nr >=3D init_nr - * and trace-nr <=3D sysctl_perf_event_max_stack, so trace_nr <=3D max_de= pth - */ - trace_nr =3D trace->nr - init_nr; - - if (trace_nr <=3D skip) + if (trace->nr <=3D skip) /* skipping more than usable stack trace */ return -EFAULT; =20 - trace_nr -=3D skip; + trace_nr =3D trace->nr - skip; trace_len =3D trace_nr * sizeof(u64); - ips =3D trace->ip + skip + init_nr; + ips =3D trace->ip + skip; hash =3D jhash2((u32 *)ips, trace_len / sizeof(u32), 0); id =3D hash & (smap->n_buckets - 1); bucket =3D READ_ONCE(smap->buckets[id]); @@ -338,8 +329,7 @@ BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, str= uct bpf_map *, map, u64, flags) { u32 max_depth =3D map->value_size / stack_map_data_size(map); - /* stack_map_alloc() checks that max_depth <=3D sysctl_perf_event_max_sta= ck */ - u32 init_nr =3D sysctl_perf_event_max_stack - max_depth; + u32 skip =3D flags & BPF_F_SKIP_FIELD_MASK; bool user =3D flags & BPF_F_USER_STACK; struct perf_callchain_entry *trace; bool kernel =3D !user; @@ -348,8 +338,12 @@ BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, st= ruct bpf_map *, map, BPF_F_FAST_STACK_CMP | BPF_F_REUSE_STACKID))) return -EINVAL; =20 - trace =3D get_perf_callchain(regs, init_nr, kernel, user, - sysctl_perf_event_max_stack, false, false); + max_depth +=3D skip; + if (max_depth > sysctl_perf_event_max_stack) + max_depth =3D sysctl_perf_event_max_stack; + + trace =3D get_perf_callchain(regs, 0, kernel, user, max_depth, + false, false); =20 if (unlikely(!trace)) /* couldn't fetch the stack trace */ @@ -440,7 +434,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struc= t task_struct *task, struct perf_callchain_entry *trace_in, void *buf, u32 size, u64 flags) { - u32 init_nr, trace_nr, copy_len, elem_size, num_elem; + u32 trace_nr, copy_len, elem_size, num_elem, max_depth; bool user_build_id =3D flags & BPF_F_USER_BUILD_ID; u32 skip =3D flags & BPF_F_SKIP_FIELD_MASK; bool user =3D flags & BPF_F_USER_STACK; @@ -465,30 +459,28 @@ static long __bpf_get_stack(struct pt_regs *regs, str= uct task_struct *task, goto err_fault; =20 num_elem =3D size / elem_size; - if (sysctl_perf_event_max_stack < num_elem) - init_nr =3D 0; - else - init_nr =3D sysctl_perf_event_max_stack - num_elem; + max_depth =3D num_elem + skip; + if (sysctl_perf_event_max_stack < max_depth) + max_depth =3D sysctl_perf_event_max_stack; =20 if (trace_in) trace =3D trace_in; else if (kernel && task) - trace =3D get_callchain_entry_for_task(task, init_nr); + trace =3D get_callchain_entry_for_task(task, max_depth); else - trace =3D get_perf_callchain(regs, init_nr, kernel, user, - sysctl_perf_event_max_stack, + trace =3D get_perf_callchain(regs, 0, kernel, user, max_depth, false, false); if (unlikely(!trace)) goto err_fault; =20 - trace_nr =3D trace->nr - init_nr; - if (trace_nr < skip) + if (trace->nr < skip) goto err_fault; =20 - trace_nr -=3D skip; + trace_nr =3D trace->nr - skip; trace_nr =3D (trace_nr <=3D num_elem) ? trace_nr : num_elem; copy_len =3D trace_nr * elem_size; - ips =3D trace->ip + skip + init_nr; + + ips =3D trace->ip + skip; if (user && user_build_id) stack_map_get_build_id_offset(buf, ips, trace_nr, user); else diff --git a/kernel/debug/kdb/kdb_support.c b/kernel/debug/kdb/kdb_support.c index df2bface866e..85cb51c4a17e 100644 --- a/kernel/debug/kdb/kdb_support.c +++ b/kernel/debug/kdb/kdb_support.c @@ -291,7 +291,7 @@ int kdb_getarea_size(void *res, unsigned long addr, siz= e_t size) */ int kdb_putarea_size(unsigned long addr, void *res, size_t size) { - int ret =3D copy_from_kernel_nofault((char *)addr, (char *)res, size); + int ret =3D copy_to_kernel_nofault((char *)addr, (char *)res, size); if (ret) { if (!KDB_STATE(SUPPRESS)) { kdb_func_printf("Bad address 0x%lx\n", addr); diff --git a/kernel/dma/debug.c b/kernel/dma/debug.c index 7a14ca29c377..f8ff598596b8 100644 --- a/kernel/dma/debug.c +++ b/kernel/dma/debug.c @@ -927,7 +927,7 @@ static __init int dma_debug_cmdline(char *str) global_disable =3D true; } =20 - return 0; + return 1; } =20 static __init int dma_debug_entries_cmdline(char *str) @@ -936,7 +936,7 @@ static __init int dma_debug_entries_cmdline(char *str) return -EINVAL; if (!get_option(&str, &nr_prealloc_entries)) nr_prealloc_entries =3D PREALLOC_DMA_DEBUG_ENTRIES; - return 0; + return 1; } =20 __setup("dma_debug=3D", dma_debug_cmdline); diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index e7f138c7636c..a1bbe0b914f1 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -655,13 +655,10 @@ void swiotlb_tbl_unmap_single(struct device *dev, phy= s_addr_t tlb_addr, void swiotlb_sync_single_for_device(struct device *dev, phys_addr_t tlb_ad= dr, size_t size, enum dma_data_direction dir) { - /* - * Unconditional bounce is necessary to avoid corruption on - * sync_*_for_cpu or dma_ummap_* when the device didn't overwrite - * the whole lengt of the bounce buffer. - */ - swiotlb_bounce(dev, tlb_addr, size, DMA_TO_DEVICE); - BUG_ON(!valid_dma_direction(dir)); + if (dir =3D=3D DMA_TO_DEVICE || dir =3D=3D DMA_BIDIRECTIONAL) + swiotlb_bounce(dev, tlb_addr, size, DMA_TO_DEVICE); + else + BUG_ON(dir !=3D DMA_FROM_DEVICE); } =20 void swiotlb_sync_single_for_cpu(struct device *dev, phys_addr_t tlb_addr, diff --git a/kernel/events/core.c b/kernel/events/core.c index e4a43d475ba6..a0e196f973b9 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -10560,8 +10560,11 @@ perf_event_parse_addr_filter(struct perf_event *ev= ent, char *fstr, } =20 /* ready to consume more filters */ + kfree(filename); + filename =3D NULL; state =3D IF_STATE_ACTION; filter =3D NULL; + kernel =3D 0; } } =20 diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 335d988bd811..c0789383807b 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -190,7 +190,7 @@ static int klp_find_object_symbol(const char *objname, = const char *name, return -EINVAL; } =20 -static int klp_resolve_symbols(Elf64_Shdr *sechdrs, const char *strtab, +static int klp_resolve_symbols(Elf_Shdr *sechdrs, const char *strtab, unsigned int symndx, Elf_Shdr *relasec, const char *sec_objname) { @@ -218,7 +218,7 @@ static int klp_resolve_symbols(Elf64_Shdr *sechdrs, con= st char *strtab, relas =3D (Elf_Rela *) relasec->sh_addr; /* For each rela in this klp relocation section */ for (i =3D 0; i < relasec->sh_size / sizeof(Elf_Rela); i++) { - sym =3D (Elf64_Sym *)sechdrs[symndx].sh_addr + ELF_R_SYM(relas[i].r_info= ); + sym =3D (Elf_Sym *)sechdrs[symndx].sh_addr + ELF_R_SYM(relas[i].r_info); if (sym->st_shndx !=3D SHN_LIVEPATCH) { pr_err("symbol %s is not marked as a livepatch symbol\n", strtab + sym->st_name); diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index d48cd608376a..55570f52de5a 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -183,11 +183,9 @@ static DECLARE_BITMAP(list_entries_in_use, MAX_LOCKDEP= _ENTRIES); static struct hlist_head lock_keys_hash[KEYHASH_SIZE]; unsigned long nr_lock_classes; unsigned long nr_zapped_classes; -#ifndef CONFIG_DEBUG_LOCKDEP -static -#endif +unsigned long max_lock_class_idx; struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; -static DECLARE_BITMAP(lock_classes_in_use, MAX_LOCKDEP_KEYS); +DECLARE_BITMAP(lock_classes_in_use, MAX_LOCKDEP_KEYS); =20 static inline struct lock_class *hlock_class(struct held_lock *hlock) { @@ -338,7 +336,7 @@ static inline void lock_release_holdtime(struct held_lo= ck *hlock) * elements. These elements are linked together by the lock_entry member in * struct lock_class. */ -LIST_HEAD(all_lock_classes); +static LIST_HEAD(all_lock_classes); static LIST_HEAD(free_lock_classes); =20 /** @@ -1252,6 +1250,7 @@ register_lock_class(struct lockdep_map *lock, unsigne= d int subclass, int force) struct lockdep_subclass_key *key; struct hlist_head *hash_head; struct lock_class *class; + int idx; =20 DEBUG_LOCKS_WARN_ON(!irqs_disabled()); =20 @@ -1317,6 +1316,9 @@ register_lock_class(struct lockdep_map *lock, unsigne= d int subclass, int force) * of classes. */ list_move_tail(&class->lock_entry, &all_lock_classes); + idx =3D class - lock_classes; + if (idx > max_lock_class_idx) + max_lock_class_idx =3D idx; =20 if (verbose(class)) { graph_unlock(); @@ -5998,6 +6000,8 @@ static void zap_class(struct pending_free *pf, struct= lock_class *class) WRITE_ONCE(class->name, NULL); nr_lock_classes--; __clear_bit(class - lock_classes, lock_classes_in_use); + if (class - lock_classes =3D=3D max_lock_class_idx) + max_lock_class_idx--; } else { WARN_ONCE(true, "%s() failed for class %s\n", __func__, class->name); @@ -6288,7 +6292,13 @@ void lockdep_reset_lock(struct lockdep_map *lock) lockdep_reset_lock_reg(lock); } =20 -/* Unregister a dynamically allocated key. */ +/* + * Unregister a dynamically allocated key. + * + * Unlike lockdep_register_key(), a search is always done to find a matchi= ng + * key irrespective of debug_locks to avoid potential invalid access to fr= eed + * memory in lock_class entry. + */ void lockdep_unregister_key(struct lock_class_key *key) { struct hlist_head *hash_head =3D keyhashentry(key); @@ -6303,10 +6313,8 @@ void lockdep_unregister_key(struct lock_class_key *k= ey) return; =20 raw_local_irq_save(flags); - if (!graph_lock()) - goto out_irq; + lockdep_lock(); =20 - pf =3D get_pending_free(); hlist_for_each_entry_rcu(k, hash_head, hash_entry) { if (k =3D=3D key) { hlist_del_rcu(&k->hash_entry); @@ -6314,11 +6322,13 @@ void lockdep_unregister_key(struct lock_class_key *= key) break; } } - WARN_ON_ONCE(!found); - __lockdep_free_key_range(pf, key, 1); - call_rcu_zapped(pf); - graph_unlock(); -out_irq: + WARN_ON_ONCE(!found && debug_locks); + if (found) { + pf =3D get_pending_free(); + __lockdep_free_key_range(pf, key, 1); + call_rcu_zapped(pf); + } + lockdep_unlock(); raw_local_irq_restore(flags); =20 /* Wait until is_dynamic_key() has finished accessing k->hash_entry. */ diff --git a/kernel/locking/lockdep_internals.h b/kernel/locking/lockdep_in= ternals.h index ecb8662e7a4e..bbe9000260d0 100644 --- a/kernel/locking/lockdep_internals.h +++ b/kernel/locking/lockdep_internals.h @@ -121,7 +121,6 @@ static const unsigned long LOCKF_USED_IN_IRQ_READ =3D =20 #define MAX_LOCKDEP_CHAIN_HLOCKS (MAX_LOCKDEP_CHAINS*5) =20 -extern struct list_head all_lock_classes; extern struct lock_chain lock_chains[]; =20 #define LOCK_USAGE_CHARS (2*XXX_LOCK_USAGE_STATES + 1) @@ -151,6 +150,10 @@ extern unsigned int nr_large_chain_blocks; =20 extern unsigned int max_lockdep_depth; extern unsigned int max_bfs_queue_depth; +extern unsigned long max_lock_class_idx; + +extern struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; +extern unsigned long lock_classes_in_use[]; =20 #ifdef CONFIG_PROVE_LOCKING extern unsigned long lockdep_count_forward_deps(struct lock_class *); @@ -205,7 +208,6 @@ struct lockdep_stats { }; =20 DECLARE_PER_CPU(struct lockdep_stats, lockdep_stats); -extern struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; =20 #define __debug_atomic_inc(ptr) \ this_cpu_inc(lockdep_stats.ptr); diff --git a/kernel/locking/lockdep_proc.c b/kernel/locking/lockdep_proc.c index b8d9a050c337..15fdc7fa5c68 100644 --- a/kernel/locking/lockdep_proc.c +++ b/kernel/locking/lockdep_proc.c @@ -24,14 +24,33 @@ =20 #include "lockdep_internals.h" =20 +/* + * Since iteration of lock_classes is done without holding the lockdep loc= k, + * it is not safe to iterate all_lock_classes list directly as the iterati= on + * may branch off to free_lock_classes or the zapped list. Iteration is do= ne + * directly on the lock_classes array by checking the lock_classes_in_use + * bitmap and max_lock_class_idx. + */ +#define iterate_lock_classes(idx, class) \ + for (idx =3D 0, class =3D lock_classes; idx <=3D max_lock_class_idx; \ + idx++, class++) + static void *l_next(struct seq_file *m, void *v, loff_t *pos) { - return seq_list_next(v, &all_lock_classes, pos); + struct lock_class *class =3D v; + + ++class; + *pos =3D class - lock_classes; + return (*pos > max_lock_class_idx) ? NULL : class; } =20 static void *l_start(struct seq_file *m, loff_t *pos) { - return seq_list_start_head(&all_lock_classes, *pos); + unsigned long idx =3D *pos; + + if (idx > max_lock_class_idx) + return NULL; + return lock_classes + idx; } =20 static void l_stop(struct seq_file *m, void *v) @@ -57,14 +76,16 @@ static void print_name(struct seq_file *m, struct lock_= class *class) =20 static int l_show(struct seq_file *m, void *v) { - struct lock_class *class =3D list_entry(v, struct lock_class, lock_entry); + struct lock_class *class =3D v; struct lock_list *entry; char usage[LOCK_USAGE_CHARS]; + int idx =3D class - lock_classes; =20 - if (v =3D=3D &all_lock_classes) { + if (v =3D=3D lock_classes) seq_printf(m, "all lock classes:\n"); + + if (!test_bit(idx, lock_classes_in_use)) return 0; - } =20 seq_printf(m, "%p", class->key); #ifdef CONFIG_DEBUG_LOCKDEP @@ -220,8 +241,11 @@ static int lockdep_stats_show(struct seq_file *m, void= *v) =20 #ifdef CONFIG_PROVE_LOCKING struct lock_class *class; + unsigned long idx; =20 - list_for_each_entry(class, &all_lock_classes, lock_entry) { + iterate_lock_classes(idx, class) { + if (!test_bit(idx, lock_classes_in_use)) + continue; =20 if (class->usage_mask =3D=3D 0) nr_unused++; @@ -254,6 +278,7 @@ static int lockdep_stats_show(struct seq_file *m, void = *v) =20 sum_forward_deps +=3D lockdep_count_forward_deps(class); } + #ifdef CONFIG_DEBUG_LOCKDEP DEBUG_LOCKS_WARN_ON(debug_atomic_read(nr_unused_locks) !=3D nr_unused); #endif @@ -345,6 +370,8 @@ static int lockdep_stats_show(struct seq_file *m, void = *v) seq_printf(m, " max bfs queue depth: %11u\n", max_bfs_queue_depth); #endif + seq_printf(m, " max lock class index: %11lu\n", + max_lock_class_idx); lockdep_stats_debug_show(m); seq_printf(m, " debug_locks: %11u\n", debug_locks); @@ -622,12 +649,16 @@ static int lock_stat_open(struct inode *inode, struct= file *file) if (!res) { struct lock_stat_data *iter =3D data->stats; struct seq_file *m =3D file->private_data; + unsigned long idx; =20 - list_for_each_entry(class, &all_lock_classes, lock_entry) { + iterate_lock_classes(idx, class) { + if (!test_bit(idx, lock_classes_in_use)) + continue; iter->class =3D class; iter->stats =3D lock_stats(class); iter++; } + data->iter_end =3D iter; =20 sort(data->stats, data->iter_end - data->stats, @@ -645,6 +676,7 @@ static ssize_t lock_stat_write(struct file *file, const= char __user *buf, size_t count, loff_t *ppos) { struct lock_class *class; + unsigned long idx; char c; =20 if (count) { @@ -654,8 +686,11 @@ static ssize_t lock_stat_write(struct file *file, cons= t char __user *buf, if (c !=3D '0') return count; =20 - list_for_each_entry(class, &all_lock_classes, lock_entry) + iterate_lock_classes(idx, class) { + if (!test_bit(idx, lock_classes_in_use)) + continue; clear_lock_stats(class); + } } return count; } diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index e6af502c2fd7..08780a466fdf 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -1328,7 +1328,7 @@ static int __init resumedelay_setup(char *str) int rc =3D kstrtouint(str, 0, &resume_delay); =20 if (rc) - return rc; + pr_warn("resumedelay: bad option string '%s'\n", str); return 1; } =20 diff --git a/kernel/power/suspend_test.c b/kernel/power/suspend_test.c index d20526c5be15..b663a97f5867 100644 --- a/kernel/power/suspend_test.c +++ b/kernel/power/suspend_test.c @@ -157,22 +157,22 @@ static int __init setup_test_suspend(char *value) value++; suspend_type =3D strsep(&value, ","); if (!suspend_type) - return 0; + return 1; =20 repeat =3D strsep(&value, ","); if (repeat) { if (kstrtou32(repeat, 0, &test_repeat_count_max)) - return 0; + return 1; } =20 for (i =3D PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) if (!strcmp(pm_labels[i], suspend_type)) { test_state_label =3D pm_labels[i]; - return 0; + return 1; } =20 printk(warn_bad_state, suspend_type); - return 0; + return 1; } __setup("test_suspend", setup_test_suspend); =20 diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 57b132b658e1..4187946a28f9 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -146,8 +146,10 @@ static int __control_devkmsg(char *str) =20 static int __init control_devkmsg(char *str) { - if (__control_devkmsg(str) < 0) + if (__control_devkmsg(str) < 0) { + pr_warn("printk.devkmsg: bad option string '%s'\n", str); return 1; + } =20 /* * Set sysctl string accordingly: @@ -166,7 +168,7 @@ static int __init control_devkmsg(char *str) */ devkmsg_log |=3D DEVKMSG_LOG_MASK_LOCK; =20 - return 0; + return 1; } __setup("printk.devkmsg=3D", control_devkmsg); =20 diff --git a/kernel/ptrace.c b/kernel/ptrace.c index f8589bf8d7dc..516ad5e65849 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -371,6 +371,26 @@ bool ptrace_may_access(struct task_struct *task, unsig= ned int mode) return !err; } =20 +static int check_ptrace_options(unsigned long data) +{ + if (data & ~(unsigned long)PTRACE_O_MASK) + return -EINVAL; + + if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) { + if (!IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) || + !IS_ENABLED(CONFIG_SECCOMP)) + return -EINVAL; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (seccomp_mode(¤t->seccomp) !=3D SECCOMP_MODE_DISABLED || + current->ptrace & PT_SUSPEND_SECCOMP) + return -EPERM; + } + return 0; +} + static int ptrace_attach(struct task_struct *task, long request, unsigned long addr, unsigned long flags) @@ -382,8 +402,16 @@ static int ptrace_attach(struct task_struct *task, lon= g request, if (seize) { if (addr !=3D 0) goto out; + /* + * This duplicates the check in check_ptrace_options() because + * ptrace_attach() and ptrace_setoptions() have historically + * used different error codes for unknown ptrace options. + */ if (flags & ~(unsigned long)PTRACE_O_MASK) goto out; + retval =3D check_ptrace_options(flags); + if (retval) + return retval; flags =3D PT_PTRACED | PT_SEIZED | (flags << PT_OPT_FLAG_SHIFT); } else { flags =3D PT_PTRACED; @@ -656,22 +684,11 @@ int ptrace_writedata(struct task_struct *tsk, char __= user *src, unsigned long ds static int ptrace_setoptions(struct task_struct *child, unsigned long data) { unsigned flags; + int ret; =20 - if (data & ~(unsigned long)PTRACE_O_MASK) - return -EINVAL; - - if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) { - if (!IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) || - !IS_ENABLED(CONFIG_SECCOMP)) - return -EINVAL; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (seccomp_mode(¤t->seccomp) !=3D SECCOMP_MODE_DISABLED || - current->ptrace & PT_SUSPEND_SECCOMP) - return -EPERM; - } + ret =3D check_ptrace_options(data); + if (ret) + return ret; =20 /* Avoid intermediate state when all opts are cleared */ flags =3D child->ptrace; diff --git a/kernel/rcu/rcu_segcblist.h b/kernel/rcu/rcu_segcblist.h index 9a19328ff251..5d405943823e 100644 --- a/kernel/rcu/rcu_segcblist.h +++ b/kernel/rcu/rcu_segcblist.h @@ -56,13 +56,13 @@ static inline long rcu_segcblist_n_cbs(struct rcu_segcb= list *rsclp) static inline void rcu_segcblist_set_flags(struct rcu_segcblist *rsclp, int flags) { - rsclp->flags |=3D flags; + WRITE_ONCE(rsclp->flags, rsclp->flags | flags); } =20 static inline void rcu_segcblist_clear_flags(struct rcu_segcblist *rsclp, int flags) { - rsclp->flags &=3D ~flags; + WRITE_ONCE(rsclp->flags, rsclp->flags & ~flags); } =20 static inline bool rcu_segcblist_test_flags(struct rcu_segcblist *rsclp, diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 28fd0cef9b1f..0e70fe0ab690 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -91,7 +91,7 @@ static struct rcu_state rcu_state =3D { .abbr =3D RCU_ABBR, .exp_mutex =3D __MUTEX_INITIALIZER(rcu_state.exp_mutex), .exp_wake_mutex =3D __MUTEX_INITIALIZER(rcu_state.exp_wake_mutex), - .ofl_lock =3D __RAW_SPIN_LOCK_UNLOCKED(rcu_state.ofl_lock), + .ofl_lock =3D __ARCH_SPIN_LOCK_UNLOCKED, }; =20 /* Dump rcu_node combining tree at boot to verify correct setup. */ @@ -1168,7 +1168,15 @@ bool rcu_lockdep_current_cpu_online(void) preempt_disable_notrace(); rdp =3D this_cpu_ptr(&rcu_data); rnp =3D rdp->mynode; - if (rdp->grpmask & rcu_rnp_online_cpus(rnp) || READ_ONCE(rnp->ofl_seq) & = 0x1) + /* + * Strictly, we care here about the case where the current CPU is + * in rcu_cpu_starting() and thus has an excuse for rdp->grpmask + * not being up to date. So arch_spin_is_locked() might have a + * false positive if it's held by some *other* CPU, but that's + * OK because that just means a false *negative* on the warning. + */ + if (rdp->grpmask & rcu_rnp_online_cpus(rnp) || + arch_spin_is_locked(&rcu_state.ofl_lock)) ret =3D true; preempt_enable_notrace(); return ret; @@ -1732,7 +1740,6 @@ static void rcu_strict_gp_boundary(void *unused) */ static noinline_for_stack bool rcu_gp_init(void) { - unsigned long firstseq; unsigned long flags; unsigned long oldmask; unsigned long mask; @@ -1775,22 +1782,17 @@ static noinline_for_stack bool rcu_gp_init(void) * of RCU's Requirements documentation. */ WRITE_ONCE(rcu_state.gp_state, RCU_GP_ONOFF); + /* Exclude CPU hotplug operations. */ rcu_for_each_leaf_node(rnp) { - // Wait for CPU-hotplug operations that might have - // started before this grace period did. - smp_mb(); // Pair with barriers used when updating ->ofl_seq to odd valu= es. - firstseq =3D READ_ONCE(rnp->ofl_seq); - if (firstseq & 0x1) - while (firstseq =3D=3D READ_ONCE(rnp->ofl_seq)) - schedule_timeout_idle(1); // Can't wake unless RCU is watching. - smp_mb(); // Pair with barriers used when updating ->ofl_seq to even val= ues. - raw_spin_lock(&rcu_state.ofl_lock); - raw_spin_lock_irq_rcu_node(rnp); + local_irq_save(flags); + arch_spin_lock(&rcu_state.ofl_lock); + raw_spin_lock_rcu_node(rnp); if (rnp->qsmaskinit =3D=3D rnp->qsmaskinitnext && !rnp->wait_blkd_tasks) { /* Nothing to do on this leaf rcu_node structure. */ - raw_spin_unlock_irq_rcu_node(rnp); - raw_spin_unlock(&rcu_state.ofl_lock); + raw_spin_unlock_rcu_node(rnp); + arch_spin_unlock(&rcu_state.ofl_lock); + local_irq_restore(flags); continue; } =20 @@ -1825,8 +1827,9 @@ static noinline_for_stack bool rcu_gp_init(void) rcu_cleanup_dead_rnp(rnp); } =20 - raw_spin_unlock_irq_rcu_node(rnp); - raw_spin_unlock(&rcu_state.ofl_lock); + raw_spin_unlock_rcu_node(rnp); + arch_spin_unlock(&rcu_state.ofl_lock); + local_irq_restore(flags); } rcu_gp_slow(gp_preinit_delay); /* Races with CPU hotplug. */ =20 @@ -4247,11 +4250,10 @@ void rcu_cpu_starting(unsigned int cpu) =20 rnp =3D rdp->mynode; mask =3D rdp->grpmask; - WRITE_ONCE(rnp->ofl_seq, rnp->ofl_seq + 1); - WARN_ON_ONCE(!(rnp->ofl_seq & 0x1)); + local_irq_save(flags); + arch_spin_lock(&rcu_state.ofl_lock); rcu_dynticks_eqs_online(); - smp_mb(); // Pair with rcu_gp_cleanup()'s ->ofl_seq barrier(). - raw_spin_lock_irqsave_rcu_node(rnp, flags); + raw_spin_lock_rcu_node(rnp); WRITE_ONCE(rnp->qsmaskinitnext, rnp->qsmaskinitnext | mask); newcpu =3D !(rnp->expmaskinitnext & mask); rnp->expmaskinitnext |=3D mask; @@ -4264,15 +4266,18 @@ void rcu_cpu_starting(unsigned int cpu) =20 /* An incoming CPU should never be blocking a grace period. */ if (WARN_ON_ONCE(rnp->qsmask & mask)) { /* RCU waiting on incoming CPU? */ + /* rcu_report_qs_rnp() *really* wants some flags to restore */ + unsigned long flags2; + + local_irq_save(flags2); rcu_disable_urgency_upon_qs(rdp); /* Report QS -after- changing ->qsmaskinitnext! */ - rcu_report_qs_rnp(mask, rnp, rnp->gp_seq, flags); + rcu_report_qs_rnp(mask, rnp, rnp->gp_seq, flags2); } else { - raw_spin_unlock_irqrestore_rcu_node(rnp, flags); + raw_spin_unlock_rcu_node(rnp); } - smp_mb(); // Pair with rcu_gp_cleanup()'s ->ofl_seq barrier(). - WRITE_ONCE(rnp->ofl_seq, rnp->ofl_seq + 1); - WARN_ON_ONCE(rnp->ofl_seq & 0x1); + arch_spin_unlock(&rcu_state.ofl_lock); + local_irq_restore(flags); smp_mb(); /* Ensure RCU read-side usage follows above initialization. */ } =20 @@ -4286,7 +4291,7 @@ void rcu_cpu_starting(unsigned int cpu) */ void rcu_report_dead(unsigned int cpu) { - unsigned long flags; + unsigned long flags, seq_flags; unsigned long mask; struct rcu_data *rdp =3D per_cpu_ptr(&rcu_data, cpu); struct rcu_node *rnp =3D rdp->mynode; /* Outgoing CPU's rdp & rnp. */ @@ -4300,10 +4305,8 @@ void rcu_report_dead(unsigned int cpu) =20 /* Remove outgoing CPU from mask in the leaf rcu_node structure. */ mask =3D rdp->grpmask; - WRITE_ONCE(rnp->ofl_seq, rnp->ofl_seq + 1); - WARN_ON_ONCE(!(rnp->ofl_seq & 0x1)); - smp_mb(); // Pair with rcu_gp_cleanup()'s ->ofl_seq barrier(). - raw_spin_lock(&rcu_state.ofl_lock); + local_irq_save(seq_flags); + arch_spin_lock(&rcu_state.ofl_lock); raw_spin_lock_irqsave_rcu_node(rnp, flags); /* Enforce GP memory-order gu= arantee. */ rdp->rcu_ofl_gp_seq =3D READ_ONCE(rcu_state.gp_seq); rdp->rcu_ofl_gp_flags =3D READ_ONCE(rcu_state.gp_flags); @@ -4314,10 +4317,8 @@ void rcu_report_dead(unsigned int cpu) } WRITE_ONCE(rnp->qsmaskinitnext, rnp->qsmaskinitnext & ~mask); raw_spin_unlock_irqrestore_rcu_node(rnp, flags); - raw_spin_unlock(&rcu_state.ofl_lock); - smp_mb(); // Pair with rcu_gp_cleanup()'s ->ofl_seq barrier(). - WRITE_ONCE(rnp->ofl_seq, rnp->ofl_seq + 1); - WARN_ON_ONCE(rnp->ofl_seq & 0x1); + arch_spin_unlock(&rcu_state.ofl_lock); + local_irq_restore(seq_flags); =20 rdp->cpu_started =3D false; } diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index 305cf6aeb408..aff4cc9303fb 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -56,8 +56,6 @@ struct rcu_node { /* Initialized from ->qsmaskinitnext at the */ /* beginning of each grace period. */ unsigned long qsmaskinitnext; - unsigned long ofl_seq; /* CPU-hotplug operation sequence count. */ - /* Online CPUs for next grace period. */ unsigned long expmask; /* CPUs or groups that need to check in */ /* to allow the current expedited GP */ /* to complete. */ @@ -358,7 +356,7 @@ struct rcu_state { const char *name; /* Name of structure. */ char abbr; /* Abbreviated name. */ =20 - raw_spinlock_t ofl_lock ____cacheline_internodealigned_in_smp; + arch_spinlock_t ofl_lock ____cacheline_internodealigned_in_smp; /* Synchronize offline with */ /* GP pre-initialization. */ }; diff --git a/kernel/resource.c b/kernel/resource.c index 5ad3eba619ba..092a6154371b 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -56,14 +56,6 @@ struct resource_constraint { =20 static DEFINE_RWLOCK(resource_lock); =20 -/* - * For memory hotplug, there is no way to free resource entries allocated - * by boot mem after the system is up. So for reusing the resource entry - * we need to remember the resource. - */ -static struct resource *bootmem_resource_free; -static DEFINE_SPINLOCK(bootmem_resource_lock); - static struct resource *next_resource(struct resource *p) { if (p->child) @@ -160,36 +152,19 @@ __initcall(ioresources_init); =20 static void free_resource(struct resource *res) { - if (!res) - return; - - if (!PageSlab(virt_to_head_page(res))) { - spin_lock(&bootmem_resource_lock); - res->sibling =3D bootmem_resource_free; - bootmem_resource_free =3D res; - spin_unlock(&bootmem_resource_lock); - } else { + /** + * If the resource was allocated using memblock early during boot + * we'll leak it here: we can only return full pages back to the + * buddy and trying to be smart and reusing them eventually in + * alloc_resource() overcomplicates resource handling. + */ + if (res && PageSlab(virt_to_head_page(res))) kfree(res); - } } =20 static struct resource *alloc_resource(gfp_t flags) { - struct resource *res =3D NULL; - - spin_lock(&bootmem_resource_lock); - if (bootmem_resource_free) { - res =3D bootmem_resource_free; - bootmem_resource_free =3D res->sibling; - } - spin_unlock(&bootmem_resource_lock); - - if (res) - memset(res, 0, sizeof(struct resource)); - else - res =3D kzalloc(sizeof(struct resource), flags); - - return res; + return kzalloc(sizeof(struct resource), flags); } =20 /* Return the conflict entry if you can't request it */ diff --git a/kernel/rseq.c b/kernel/rseq.c index 6d45ac3dae7f..97ac20b4f738 100644 --- a/kernel/rseq.c +++ b/kernel/rseq.c @@ -128,10 +128,10 @@ static int rseq_get_rseq_cs(struct task_struct *t, st= ruct rseq_cs *rseq_cs) int ret; =20 #ifdef CONFIG_64BIT - if (get_user(ptr, &t->rseq->rseq_cs.ptr64)) + if (get_user(ptr, &t->rseq->rseq_cs)) return -EFAULT; #else - if (copy_from_user(&ptr, &t->rseq->rseq_cs.ptr64, sizeof(ptr))) + if (copy_from_user(&ptr, &t->rseq->rseq_cs, sizeof(ptr))) return -EFAULT; #endif if (!ptr) { @@ -217,9 +217,9 @@ static int clear_rseq_cs(struct task_struct *t) * Set rseq_cs to NULL. */ #ifdef CONFIG_64BIT - return put_user(0UL, &t->rseq->rseq_cs.ptr64); + return put_user(0UL, &t->rseq->rseq_cs); #else - if (clear_user(&t->rseq->rseq_cs.ptr64, sizeof(t->rseq->rseq_cs.ptr64))) + if (clear_user(&t->rseq->rseq_cs, sizeof(t->rseq->rseq_cs))) return -EFAULT; return 0; #endif diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 65082cab2906..0e4b8214af31 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -36,6 +36,7 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_rt_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_dl_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_irq_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_se_tp); +EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_thermal_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_cpu_capacity_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_overutilized_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_util_est_cfs_tp); diff --git a/kernel/sched/cpuacct.c b/kernel/sched/cpuacct.c index ab67d97a8442..cacc2076ad21 100644 --- a/kernel/sched/cpuacct.c +++ b/kernel/sched/cpuacct.c @@ -328,12 +328,13 @@ static struct cftype files[] =3D { */ void cpuacct_charge(struct task_struct *tsk, u64 cputime) { + unsigned int cpu =3D task_cpu(tsk); struct cpuacct *ca; =20 rcu_read_lock(); =20 for (ca =3D task_ca(tsk); ca; ca =3D parent_ca(ca)) - __this_cpu_add(*ca->cpuusage, cputime); + *per_cpu_ptr(ca->cpuusage, cpu) +=3D cputime; =20 rcu_read_unlock(); } diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedu= til.c index e7af18857371..7f6bb37d3a2f 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -289,6 +289,7 @@ static void sugov_iowait_apply(struct sugov_cpu *sg_cpu= , u64 time) * into the same scale so we can compare. */ boost =3D (sg_cpu->iowait_boost * sg_cpu->max) >> SCHED_CAPACITY_SHIFT; + boost =3D uclamp_rq_util_with(cpu_rq(sg_cpu->cpu), boost, NULL); if (sg_cpu->util < boost) sg_cpu->util =3D boost; } diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index d2c072b0ef01..62f0cf842277 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -2240,12 +2240,6 @@ static int push_dl_task(struct rq *rq) return 0; =20 retry: - if (is_migration_disabled(next_task)) - return 0; - - if (WARN_ON(next_task =3D=3D rq->curr)) - return 0; - /* * If next_task preempts rq->curr, and rq->curr * can move away, it makes sense to just reschedule @@ -2258,6 +2252,12 @@ static int push_dl_task(struct rq *rq) return 0; } =20 + if (is_migration_disabled(next_task)) + return 0; + + if (WARN_ON(next_task =3D=3D rq->curr)) + return 0; + /* We might release rq lock */ get_task_struct(next_task); =20 diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c index 7dcbaa31c5d9..50e05c8d0d61 100644 --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -931,25 +931,15 @@ void print_numa_stats(struct seq_file *m, int node, u= nsigned long tsf, static void sched_show_numa(struct task_struct *p, struct seq_file *m) { #ifdef CONFIG_NUMA_BALANCING - struct mempolicy *pol; - if (p->mm) P(mm->numa_scan_seq); =20 - task_lock(p); - pol =3D p->mempolicy; - if (pol && !(pol->flags & MPOL_F_MORON)) - pol =3D NULL; - mpol_get(pol); - task_unlock(p); - P(numa_pages_migrated); P(numa_preferred_nid); P(total_numa_faults); SEQ_printf(m, "current_node=3D%d, numa_group_id=3D%d\n", task_node(p), task_numa_group_id(p)); show_numa_stats(p, m); - mpol_put(pol); #endif } =20 diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 069e01772d92..9637766e220d 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -9062,9 +9062,10 @@ static bool update_pick_idlest(struct sched_group *i= dlest, * This is an approximation as the number of running tasks may not be * related to the number of busy CPUs due to sched_setaffinity. */ -static inline bool allow_numa_imbalance(int dst_running, int dst_weight) +static inline bool +allow_numa_imbalance(unsigned int running, unsigned int weight) { - return (dst_running < (dst_weight >> 2)); + return (running < (weight >> 2)); } =20 /* @@ -9198,12 +9199,13 @@ find_idlest_group(struct sched_domain *sd, struct t= ask_struct *p, int this_cpu) return idlest; #endif /* - * Otherwise, keep the task on this node to stay close - * its wakeup source and improve locality. If there is - * a real need of migration, periodic load balance will - * take care of it. + * Otherwise, keep the task close to the wakeup source + * and improve locality if the number of running tasks + * would remain below threshold where an imbalance is + * allowed. If there is a real need of migration, + * periodic load balance will take care of it. */ - if (allow_numa_imbalance(local_sgs.sum_nr_running, sd->span_weight)) + if (allow_numa_imbalance(local_sgs.sum_nr_running + 1, local_sgs.group_= weight)) return NULL; } =20 @@ -9409,7 +9411,7 @@ static inline void calculate_imbalance(struct lb_env = *env, struct sd_lb_stats *s /* Consider allowing a small imbalance between NUMA groups */ if (env->sd->flags & SD_NUMA) { env->imbalance =3D adjust_numa_imbalance(env->imbalance, - busiest->sum_nr_running, busiest->group_weight); + local->sum_nr_running + 1, local->group_weight); } =20 return; diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 7b4f4fbbb404..14f273c29518 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -2026,6 +2026,16 @@ static int push_rt_task(struct rq *rq, bool pull) return 0; =20 retry: + /* + * It's possible that the next_task slipped in of + * higher priority than current. If that's the case + * just reschedule current. + */ + if (unlikely(next_task->prio < rq->curr->prio)) { + resched_curr(rq); + return 0; + } + if (is_migration_disabled(next_task)) { struct task_struct *push_task =3D NULL; int cpu; @@ -2033,6 +2043,18 @@ static int push_rt_task(struct rq *rq, bool pull) if (!pull || rq->push_busy) return 0; =20 + /* + * Invoking find_lowest_rq() on anything but an RT task doesn't + * make sense. Per the above priority check, curr has to + * be of higher priority than next_task, so no need to + * reschedule when bailing out. + * + * Note that the stoppers are masqueraded as SCHED_FIFO + * (cf. sched_set_stop_task()), so we can't rely on rt_task(). + */ + if (rq->curr->sched_class !=3D &rt_sched_class) + return 0; + cpu =3D find_lowest_rq(rq->curr); if (cpu =3D=3D -1 || cpu =3D=3D rq->cpu) return 0; @@ -2057,16 +2079,6 @@ static int push_rt_task(struct rq *rq, bool pull) if (WARN_ON(next_task =3D=3D rq->curr)) return 0; =20 - /* - * It's possible that the next_task slipped in of - * higher priority than current. If that's the case - * just reschedule current. - */ - if (unlikely(next_task->prio < rq->curr->prio)) { - resched_curr(rq); - return 0; - } - /* We might release rq lock */ get_task_struct(next_task); =20 diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 5816ad79cce8..1e6befe0d78c 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -3654,12 +3654,17 @@ static char *trace_iter_expand_format(struct trace_= iterator *iter) } =20 /* Returns true if the string is safe to dereference from an event */ -static bool trace_safe_str(struct trace_iterator *iter, const char *str) +static bool trace_safe_str(struct trace_iterator *iter, const char *str, + bool star, int len) { unsigned long addr =3D (unsigned long)str; struct trace_event *trace_event; struct trace_event_call *event; =20 + /* Ignore strings with no length */ + if (star && !len) + return true; + /* OK if part of the event data */ if ((addr >=3D (unsigned long)iter->ent) && (addr < (unsigned long)iter->ent + iter->ent_size)) @@ -3845,7 +3850,7 @@ void trace_check_vprintf(struct trace_iterator *iter,= const char *fmt, * instead. See samples/trace_events/trace-events-sample.h * for reference. */ - if (WARN_ONCE(!trace_safe_str(iter, str), + if (WARN_ONCE(!trace_safe_str(iter, str, star, len), "fmt: '%s' current_buffer: '%s'", fmt, show_buffer(&iter->seq))) { int ret; diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 92be9cb1d7d4..99f4bae375ff 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -40,6 +40,14 @@ static LIST_HEAD(ftrace_generic_fields); static LIST_HEAD(ftrace_common_fields); static bool eventdir_initialized; =20 +static LIST_HEAD(module_strings); + +struct module_string { + struct list_head next; + struct module *module; + char *str; +}; + #define GFP_TRACE (GFP_KERNEL | __GFP_ZERO) =20 static struct kmem_cache *field_cachep; @@ -2633,6 +2641,76 @@ static void update_event_printk(struct trace_event_c= all *call, } } =20 +static void add_str_to_module(struct module *module, char *str) +{ + struct module_string *modstr; + + modstr =3D kmalloc(sizeof(*modstr), GFP_KERNEL); + + /* + * If we failed to allocate memory here, then we'll just + * let the str memory leak when the module is removed. + * If this fails to allocate, there's worse problems than + * a leaked string on module removal. + */ + if (WARN_ON_ONCE(!modstr)) + return; + + modstr->module =3D module; + modstr->str =3D str; + + list_add(&modstr->next, &module_strings); +} + +static void update_event_fields(struct trace_event_call *call, + struct trace_eval_map *map) +{ + struct ftrace_event_field *field; + struct list_head *head; + char *ptr; + char *str; + int len =3D strlen(map->eval_string); + + /* Dynamic events should never have field maps */ + if (WARN_ON_ONCE(call->flags & TRACE_EVENT_FL_DYNAMIC)) + return; + + head =3D trace_get_fields(call); + list_for_each_entry(field, head, link) { + ptr =3D strchr(field->type, '['); + if (!ptr) + continue; + ptr++; + + if (!isalpha(*ptr) && *ptr !=3D '_') + continue; + + if (strncmp(map->eval_string, ptr, len) !=3D 0) + continue; + + str =3D kstrdup(field->type, GFP_KERNEL); + if (WARN_ON_ONCE(!str)) + return; + ptr =3D str + (ptr - field->type); + ptr =3D eval_replace(ptr, map, len); + /* enum/sizeof string smaller than value */ + if (WARN_ON_ONCE(!ptr)) { + kfree(str); + continue; + } + + /* + * If the event is part of a module, then we need to free the string + * when the module is removed. Otherwise, it will stay allocated + * until a reboot. + */ + if (call->module) + add_str_to_module(call->module, str); + + field->type =3D str; + } +} + void trace_event_eval_update(struct trace_eval_map **map, int len) { struct trace_event_call *call, *p; @@ -2668,6 +2746,7 @@ void trace_event_eval_update(struct trace_eval_map **= map, int len) first =3D false; } update_event_printk(call, map[i]); + update_event_fields(call, map[i]); } } } @@ -2853,6 +2932,7 @@ static void trace_module_add_events(struct module *mo= d) static void trace_module_remove_events(struct module *mod) { struct trace_event_call *call, *p; + struct module_string *modstr, *m; =20 down_write(&trace_event_sem); list_for_each_entry_safe(call, p, &ftrace_events, list) { @@ -2861,6 +2941,14 @@ static void trace_module_remove_events(struct module= *mod) if (call->module =3D=3D mod) __trace_remove_event_call(call); } + /* Check for any strings allocade for this module */ + list_for_each_entry_safe(modstr, m, &module_strings, next) { + if (modstr->module !=3D mod) + continue; + list_del(&modstr->next); + kfree(modstr->str); + kfree(modstr); + } up_write(&trace_event_sem); =20 /* diff --git a/kernel/watch_queue.c b/kernel/watch_queue.c index 055bc20ecdda..b1ae7c9c3b47 100644 --- a/kernel/watch_queue.c +++ b/kernel/watch_queue.c @@ -274,7 +274,7 @@ long watch_queue_set_size(struct pipe_inode_info *pipe,= unsigned int nr_notes) return 0; =20 error_p: - for (i =3D 0; i < nr_pages; i++) + while (--i >=3D 0) __free_page(pages[i]); kfree(pages); error: @@ -373,6 +373,7 @@ static void __put_watch_queue(struct kref *kref) =20 for (i =3D 0; i < wqueue->nr_pages; i++) __free_page(wqueue->notes[i]); + kfree(wqueue->notes); bitmap_free(wqueue->notes_bitmap); =20 wfilter =3D rcu_access_pointer(wqueue->filter); @@ -398,6 +399,7 @@ static void free_watch(struct rcu_head *rcu) put_watch_queue(rcu_access_pointer(watch->queue)); atomic_dec(&watch->cred->user->nr_watches); put_cred(watch->cred); + kfree(watch); } =20 static void __put_watch(struct kref *kref) diff --git a/lib/kunit/try-catch.c b/lib/kunit/try-catch.c index 0dd434e40487..71e5c5853099 100644 --- a/lib/kunit/try-catch.c +++ b/lib/kunit/try-catch.c @@ -52,7 +52,7 @@ static unsigned long kunit_test_timeout(void) * If tests timeout due to exceeding sysctl_hung_task_timeout_secs, * the task will be killed and an oops generated. */ - return 300 * MSEC_PER_SEC; /* 5 min */ + return 300 * msecs_to_jiffies(MSEC_PER_SEC); /* 5 min */ } =20 void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context) diff --git a/lib/raid6/test/Makefile b/lib/raid6/test/Makefile index a4c7cd74cff5..4fb7700a741b 100644 --- a/lib/raid6/test/Makefile +++ b/lib/raid6/test/Makefile @@ -4,6 +4,8 @@ # from userspace. # =20 +pound :=3D \# + CC =3D gcc OPTFLAGS =3D -O2 # Adjust as desired CFLAGS =3D -I.. -I ../../../include -g $(OPTFLAGS) @@ -42,7 +44,7 @@ else ifeq ($(HAS_NEON),yes) OBJS +=3D neon.o neon1.o neon2.o neon4.o neon8.o recov_neon.o re= cov_neon_inner.o CFLAGS +=3D -DCONFIG_KERNEL_MODE_NEON=3D1 else - HAS_ALTIVEC :=3D $(shell printf '\#include \nvector int= a;\n' |\ + HAS_ALTIVEC :=3D $(shell printf '$(pound)include \nvect= or int a;\n' |\ gcc -c -x c - >/dev/null && rm ./-.o && echo yes) ifeq ($(HAS_ALTIVEC),yes) CFLAGS +=3D -I../../../arch/powerpc/include diff --git a/lib/raid6/test/test.c b/lib/raid6/test/test.c index a3cf071941ab..841a55242aba 100644 --- a/lib/raid6/test/test.c +++ b/lib/raid6/test/test.c @@ -19,7 +19,6 @@ #define NDISKS 16 /* Including P and Q */ =20 const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(PAGE_SI= ZE))); -struct raid6_calls raid6_call; =20 char *dataptrs[NDISKS]; char data[NDISKS][PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); diff --git a/lib/test_kmod.c b/lib/test_kmod.c index ce1589391413..cb800b1d0d99 100644 --- a/lib/test_kmod.c +++ b/lib/test_kmod.c @@ -1149,6 +1149,7 @@ static struct kmod_test_device *register_test_dev_kmo= d(void) if (ret) { pr_err("could not register misc device: %d\n", ret); free_test_dev_kmod(test_dev); + test_dev =3D NULL; goto out; } =20 diff --git a/lib/test_lockup.c b/lib/test_lockup.c index 906b598740a7..c3fd87d6c2dd 100644 --- a/lib/test_lockup.c +++ b/lib/test_lockup.c @@ -417,9 +417,14 @@ static bool test_kernel_ptr(unsigned long addr, int si= ze) return false; =20 /* should be at least readable kernel address */ - if (access_ok(ptr, 1) || - access_ok(ptr + size - 1, 1) || - get_kernel_nofault(buf, ptr) || + if (!IS_ENABLED(CONFIG_ALTERNATE_USER_ADDRESS_SPACE) && + (access_ok((void __user *)ptr, 1) || + access_ok((void __user *)ptr + size - 1, 1))) { + pr_err("user space ptr invalid in kernel: %#lx\n", addr); + return true; + } + + if (get_kernel_nofault(buf, ptr) || get_kernel_nofault(buf, ptr + size - 1)) { pr_err("invalid kernel ptr: %#lx\n", addr); return true; diff --git a/lib/test_xarray.c b/lib/test_xarray.c index 8b1c318189ce..e77d4856442c 100644 --- a/lib/test_xarray.c +++ b/lib/test_xarray.c @@ -1463,6 +1463,25 @@ static noinline void check_create_range_4(struct xar= ray *xa, XA_BUG_ON(xa, !xa_empty(xa)); } =20 +static noinline void check_create_range_5(struct xarray *xa, + unsigned long index, unsigned int order) +{ + XA_STATE_ORDER(xas, xa, index, order); + unsigned int i; + + xa_store_order(xa, index, order, xa_mk_index(index), GFP_KERNEL); + + for (i =3D 0; i < order + 10; i++) { + do { + xas_lock(&xas); + xas_create_range(&xas); + xas_unlock(&xas); + } while (xas_nomem(&xas, GFP_KERNEL)); + } + + xa_destroy(xa); +} + static noinline void check_create_range(struct xarray *xa) { unsigned int order; @@ -1490,6 +1509,9 @@ static noinline void check_create_range(struct xarray= *xa) check_create_range_4(xa, (3U << order) + 1, order); check_create_range_4(xa, (3U << order) - 1, order); check_create_range_4(xa, (1U << 24) + 1, order); + + check_create_range_5(xa, 0, order); + check_create_range_5(xa, (1U << order), order); } =20 check_create_range_3(); diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 58d5e567f836..937dd643008d 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -49,10 +49,15 @@ =20 #include /* for PAGE_SIZE */ #include /* cpu_to_le16 */ +#include =20 #include #include "kstrtox.h" =20 +/* Disable pointer hashing if requested */ +bool no_hash_pointers __ro_after_init; +EXPORT_SYMBOL_GPL(no_hash_pointers); + static noinline unsigned long long simple_strntoull(const char *startp, si= ze_t max_chars, char **endp, unsigned int base) { const char *cp; @@ -848,6 +853,19 @@ static char *ptr_to_id(char *buf, char *end, const voi= d *ptr, return pointer_string(buf, end, (const void *)hashval, spec); } =20 +static char *default_pointer(char *buf, char *end, const void *ptr, + struct printf_spec spec) +{ + /* + * default is to _not_ leak addresses, so hash before printing, + * unless no_hash_pointers is specified on the command line. + */ + if (unlikely(no_hash_pointers)) + return pointer_string(buf, end, ptr, spec); + + return ptr_to_id(buf, end, ptr, spec); +} + int kptr_restrict __read_mostly; =20 static noinline_for_stack @@ -857,7 +875,7 @@ char *restricted_pointer(char *buf, char *end, const vo= id *ptr, switch (kptr_restrict) { case 0: /* Handle as %p, hash and do _not_ leak addresses. */ - return ptr_to_id(buf, end, ptr, spec); + return default_pointer(buf, end, ptr, spec); case 1: { const struct cred *cred; =20 @@ -1771,7 +1789,7 @@ char *fourcc_string(char *buf, char *end, const u32 *= fourcc, char output[sizeof("0123 little-endian (0x01234567)")]; char *p =3D output; unsigned int i; - u32 val; + u32 orig, val; =20 if (fmt[1] !=3D 'c' || fmt[2] !=3D 'c') return error_string(buf, end, "(%p4?)", spec); @@ -1779,21 +1797,22 @@ char *fourcc_string(char *buf, char *end, const u32= *fourcc, if (check_pointer(&buf, end, fourcc, spec)) return buf; =20 - val =3D *fourcc & ~BIT(31); + orig =3D get_unaligned(fourcc); + val =3D orig & ~BIT(31); =20 - for (i =3D 0; i < sizeof(*fourcc); i++) { + for (i =3D 0; i < sizeof(u32); i++) { unsigned char c =3D val >> (i * 8); =20 /* Print non-control ASCII characters as-is, dot otherwise */ *p++ =3D isascii(c) && isprint(c) ? c : '.'; } =20 - strcpy(p, *fourcc & BIT(31) ? " big-endian" : " little-endian"); + strcpy(p, orig & BIT(31) ? " big-endian" : " little-endian"); p +=3D strlen(p); =20 *p++ =3D ' '; *p++ =3D '('; - p =3D special_hex_number(p, output + sizeof(output) - 2, *fourcc, sizeof(= u32)); + p =3D special_hex_number(p, output + sizeof(output) - 2, orig, sizeof(u32= )); *p++ =3D ')'; *p =3D '\0'; =20 @@ -2233,10 +2252,6 @@ char *fwnode_string(char *buf, char *end, struct fwn= ode_handle *fwnode, return widen_string(buf, buf - buf_start, end, spec); } =20 -/* Disable pointer hashing if requested */ -bool no_hash_pointers __ro_after_init; -EXPORT_SYMBOL_GPL(no_hash_pointers); - int __init no_hash_pointers_enable(char *str) { if (no_hash_pointers) @@ -2465,7 +2480,7 @@ char *pointer(const char *fmt, char *buf, char *end, = void *ptr, case 'e': /* %pe with a non-ERR_PTR gets treated as plain %p */ if (!IS_ERR(ptr)) - break; + return default_pointer(buf, end, ptr, spec); return err_ptr(buf, end, ptr, spec); case 'u': case 'k': @@ -2475,16 +2490,9 @@ char *pointer(const char *fmt, char *buf, char *end,= void *ptr, default: return error_string(buf, end, "(einval)", spec); } + default: + return default_pointer(buf, end, ptr, spec); } - - /* - * default is to _not_ leak addresses, so hash before printing, - * unless no_hash_pointers is specified on the command line. - */ - if (unlikely(no_hash_pointers)) - return pointer_string(buf, end, ptr, spec); - else - return ptr_to_id(buf, end, ptr, spec); } =20 /* diff --git a/lib/xarray.c b/lib/xarray.c index f5d8f54907b4..96e2d7748e5a 100644 --- a/lib/xarray.c +++ b/lib/xarray.c @@ -722,6 +722,8 @@ void xas_create_range(struct xa_state *xas) =20 for (;;) { struct xa_node *node =3D xas->xa_node; + if (node->shift >=3D shift) + break; xas->xa_node =3D xa_parent_locked(xas->xa, node); xas->xa_offset =3D node->offset - 1; if (node->offset !=3D 0) @@ -1079,6 +1081,7 @@ void xas_split(struct xa_state *xas, void *entry, uns= igned int order) xa_mk_node(child)); if (xa_is_value(curr)) values--; + xas_update(xas, child); } else { unsigned int canon =3D offset - xas->xa_sibs; =20 @@ -1093,6 +1096,7 @@ void xas_split(struct xa_state *xas, void *entry, uns= igned int order) } while (offset-- > xas->xa_offset); =20 node->nr_values +=3D values; + xas_update(xas, node); } EXPORT_SYMBOL_GPL(xas_split); #endif diff --git a/mm/kmemleak.c b/mm/kmemleak.c index adbe5aa01184..b78861b8e013 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -789,6 +789,8 @@ static void add_scan_area(unsigned long ptr, size_t siz= e, gfp_t gfp) unsigned long flags; struct kmemleak_object *object; struct kmemleak_scan_area *area =3D NULL; + unsigned long untagged_ptr; + unsigned long untagged_objp; =20 object =3D find_and_get_object(ptr, 1); if (!object) { @@ -797,6 +799,9 @@ static void add_scan_area(unsigned long ptr, size_t siz= e, gfp_t gfp) return; } =20 + untagged_ptr =3D (unsigned long)kasan_reset_tag((void *)ptr); + untagged_objp =3D (unsigned long)kasan_reset_tag((void *)object->pointer); + if (scan_area_cache) area =3D kmem_cache_alloc(scan_area_cache, gfp_kmemleak_mask(gfp)); =20 @@ -808,8 +813,8 @@ static void add_scan_area(unsigned long ptr, size_t siz= e, gfp_t gfp) goto out_unlock; } if (size =3D=3D SIZE_MAX) { - size =3D object->pointer + object->size - ptr; - } else if (ptr + size > object->pointer + object->size) { + size =3D untagged_objp + object->size - untagged_ptr; + } else if (untagged_ptr + size > untagged_objp + object->size) { kmemleak_warn("Scan area larger than object 0x%08lx\n", ptr); dump_object_info(object); kmem_cache_free(scan_area_cache, area); diff --git a/mm/madvise.c b/mm/madvise.c index 8c927202bbe6..7a2679a7307f 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -1287,8 +1287,7 @@ SYSCALL_DEFINE5(process_madvise, int, pidfd, const st= ruct iovec __user *, vec, iov_iter_advance(&iter, iovec.iov_len); } =20 - if (ret =3D=3D 0) - ret =3D total_len - iov_iter_count(&iter); + ret =3D (total_len - iov_iter_count(&iter)) ? : ret; =20 release_mm: mmput(mm); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index e57b14f96615..317035d97c0c 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -7038,7 +7038,7 @@ static int __init cgroup_memory(char *s) if (!strcmp(token, "nokmem")) cgroup_memory_nokmem =3D true; } - return 0; + return 1; } __setup("cgroup.memory=3D", cgroup_memory); =20 diff --git a/mm/memory.c b/mm/memory.c index 8f1de811a1dc..10bf23234fcc 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1304,6 +1304,35 @@ copy_page_range(struct vm_area_struct *dst_vma, stru= ct vm_area_struct *src_vma) return ret; } =20 +/* Whether we should zap all COWed (private) pages too */ +static inline bool should_zap_cows(struct zap_details *details) +{ + /* By default, zap all pages */ + if (!details) + return true; + + /* Or, we zap COWed pages only if the caller wants to */ + return !details->zap_mapping; +} + +/* + * We set details->zap_mappings when we want to unmap shared but keep priv= ate + * pages. Return true if skip zapping this page, false otherwise. + */ +static inline bool +zap_skip_check_mapping(struct zap_details *details, struct page *page) +{ + /* If we can make a decision without *page.. */ + if (should_zap_cows(details)) + return false; + + /* E.g. the caller passes NULL for the case of a zero page */ + if (!page) + return false; + + return details->zap_mapping !=3D page_rmapping(page); +} + static unsigned long zap_pte_range(struct mmu_gather *tlb, struct vm_area_struct *vma, pmd_t *pmd, unsigned long addr, unsigned long end, @@ -1382,17 +1411,24 @@ static unsigned long zap_pte_range(struct mmu_gathe= r *tlb, continue; } =20 - /* If details->check_mapping, we leave swap entries. */ - if (unlikely(details)) - continue; - - if (!non_swap_entry(entry)) + if (!non_swap_entry(entry)) { + /* Genuine swap entry, hence a private anon page */ + if (!should_zap_cows(details)) + continue; rss[MM_SWAPENTS]--; - else if (is_migration_entry(entry)) { + } else if (is_migration_entry(entry)) { struct page *page; =20 page =3D pfn_swap_entry_to_page(entry); + if (zap_skip_check_mapping(details, page)) + continue; rss[mm_counter(page)]--; + } else if (is_hwpoison_entry(entry)) { + if (!should_zap_cows(details)) + continue; + } else { + /* We should have covered all the swap entry types */ + WARN_ON_ONCE(1); } if (unlikely(!free_swap_and_cache(entry))) print_bad_pte(vma, addr, ptent, NULL); @@ -3852,11 +3888,20 @@ static vm_fault_t __do_fault(struct vm_fault *vmf) return ret; =20 if (unlikely(PageHWPoison(vmf->page))) { - if (ret & VM_FAULT_LOCKED) - unlock_page(vmf->page); - put_page(vmf->page); + struct page *page =3D vmf->page; + vm_fault_t poisonret =3D VM_FAULT_HWPOISON; + if (ret & VM_FAULT_LOCKED) { + if (page_mapped(page)) + unmap_mapping_pages(page_mapping(page), + page->index, 1, false); + /* Retry if a clean page was removed from the cache. */ + if (invalidate_inode_page(page)) + poisonret =3D VM_FAULT_NOPAGE; + unlock_page(page); + } + put_page(page); vmf->page =3D NULL; - return VM_FAULT_HWPOISON; + return poisonret; } =20 if (unlikely(!(ret & VM_FAULT_LOCKED))) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index f6248affaf38..dd5daddb6257 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -783,7 +783,6 @@ static int vma_replace_policy(struct vm_area_struct *vm= a, static int mbind_range(struct mm_struct *mm, unsigned long start, unsigned long end, struct mempolicy *new_pol) { - struct vm_area_struct *next; struct vm_area_struct *prev; struct vm_area_struct *vma; int err =3D 0; @@ -798,8 +797,7 @@ static int mbind_range(struct mm_struct *mm, unsigned l= ong start, if (start > vma->vm_start) prev =3D vma; =20 - for (; vma && vma->vm_start < end; prev =3D vma, vma =3D next) { - next =3D vma->vm_next; + for (; vma && vma->vm_start < end; prev =3D vma, vma =3D vma->vm_next) { vmstart =3D max(start, vma->vm_start); vmend =3D min(end, vma->vm_end); =20 @@ -813,10 +811,6 @@ static int mbind_range(struct mm_struct *mm, unsigned = long start, new_pol, vma->vm_userfaultfd_ctx); if (prev) { vma =3D prev; - next =3D vma->vm_next; - if (mpol_equal(vma_policy(vma), new_pol)) - continue; - /* vma_merge() joined vma && vma->next, case 8 */ goto replace; } if (vma->vm_start !=3D vmstart) { diff --git a/mm/mlock.c b/mm/mlock.c index e263d62ae2d0..c79d09f5e506 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -827,13 +827,12 @@ int user_shm_lock(size_t size, struct ucounts *ucount= s) =20 locked =3D (size + PAGE_SIZE - 1) >> PAGE_SHIFT; lock_limit =3D rlimit(RLIMIT_MEMLOCK); - if (lock_limit =3D=3D RLIM_INFINITY) - allowed =3D 1; - lock_limit >>=3D PAGE_SHIFT; + if (lock_limit !=3D RLIM_INFINITY) + lock_limit >>=3D PAGE_SHIFT; spin_lock(&shmlock_user_lock); memlock =3D inc_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_MEMLOCK, locked); =20 - if (!allowed && (memlock =3D=3D LONG_MAX || memlock > lock_limit) && !cap= able(CAP_IPC_LOCK)) { + if ((memlock =3D=3D LONG_MAX || memlock > lock_limit) && !capable(CAP_IPC= _LOCK)) { dec_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_MEMLOCK, locked); goto out; } diff --git a/mm/mmap.c b/mm/mmap.c index bfb0ea164a90..22f2469bb245 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -2550,7 +2550,7 @@ static int __init cmdline_parse_stack_guard_gap(char = *p) if (!*endptr) stack_guard_gap =3D val << PAGE_SHIFT; =20 - return 0; + return 1; } __setup("stack_guard_gap=3D", cmdline_parse_stack_guard_gap); =20 diff --git a/mm/page_alloc.c b/mm/page_alloc.c index d9492eaa4713..18365f284d8c 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -7910,10 +7910,17 @@ static void __init find_zone_movable_pfns_for_nodes= (void) =20 out2: /* Align start of ZONE_MOVABLE on all nids to MAX_ORDER_NR_PAGES */ - for (nid =3D 0; nid < MAX_NUMNODES; nid++) + for (nid =3D 0; nid < MAX_NUMNODES; nid++) { + unsigned long start_pfn, end_pfn; + zone_movable_pfn[nid] =3D roundup(zone_movable_pfn[nid], MAX_ORDER_NR_PAGES); =20 + get_pfn_range_for_nid(nid, &start_pfn, &end_pfn); + if (zone_movable_pfn[nid] >=3D end_pfn) + zone_movable_pfn[nid] =3D 0; + } + out: /* restore the node_state */ node_states[N_MEMORY] =3D saved_node_state; diff --git a/mm/slab.c b/mm/slab.c index ca4822f6b2b6..6c2013c214a7 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -3429,6 +3429,7 @@ static __always_inline void __cache_free(struct kmem_= cache *cachep, void *objp, =20 if (is_kfence_address(objp)) { kmemleak_free_recursive(objp, cachep->flags); + memcg_slab_free_hook(cachep, &objp, 1); __kfence_free(objp); return; } diff --git a/mm/usercopy.c b/mm/usercopy.c index b3de3c4eefba..540968b481e7 100644 --- a/mm/usercopy.c +++ b/mm/usercopy.c @@ -294,7 +294,10 @@ static bool enable_checks __initdata =3D true; =20 static int __init parse_hardened_usercopy(char *str) { - return strtobool(str, &enable_checks); + if (strtobool(str, &enable_checks)) + pr_warn("Invalid option string for hardened_usercopy: '%s'\n", + str); + return 1; } =20 __setup("hardened_usercopy=3D", parse_hardened_usercopy); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index bd669c95b9a7..55900496ac33 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -669,7 +669,9 @@ static void le_conn_timeout(struct work_struct *work) if (conn->role =3D=3D HCI_ROLE_SLAVE) { /* Disable LE Advertising */ le_disable_advertising(hdev); + hci_dev_lock(hdev); hci_le_conn_failed(conn, HCI_ERROR_ADVERTISING_TIMEOUT); + hci_dev_unlock(hdev); return; } =20 diff --git a/net/can/isotp.c b/net/can/isotp.c index d2a430b6a13b..a95d171b3a64 100644 --- a/net/can/isotp.c +++ b/net/can/isotp.c @@ -1005,26 +1005,29 @@ static int isotp_recvmsg(struct socket *sock, struc= t msghdr *msg, size_t size, { struct sock *sk =3D sock->sk; struct sk_buff *skb; - int err =3D 0; - int noblock; + struct isotp_sock *so =3D isotp_sk(sk); + int noblock =3D flags & MSG_DONTWAIT; + int ret =3D 0; =20 - noblock =3D flags & MSG_DONTWAIT; - flags &=3D ~MSG_DONTWAIT; + if (flags & ~(MSG_DONTWAIT | MSG_TRUNC | MSG_PEEK)) + return -EINVAL; =20 - skb =3D skb_recv_datagram(sk, flags, noblock, &err); + if (!so->bound) + return -EADDRNOTAVAIL; + + flags &=3D ~MSG_DONTWAIT; + skb =3D skb_recv_datagram(sk, flags, noblock, &ret); if (!skb) - return err; + return ret; =20 if (size < skb->len) msg->msg_flags |=3D MSG_TRUNC; else size =3D skb->len; =20 - err =3D memcpy_to_msg(msg, skb->data, size); - if (err < 0) { - skb_free_datagram(sk, skb); - return err; - } + ret =3D memcpy_to_msg(msg, skb->data, size); + if (ret < 0) + goto out_err; =20 sock_recv_timestamp(msg, sk, skb); =20 @@ -1034,9 +1037,13 @@ static int isotp_recvmsg(struct socket *sock, struct= msghdr *msg, size_t size, memcpy(msg->msg_name, skb->cb, msg->msg_namelen); } =20 + /* set length of return value */ + ret =3D (flags & MSG_TRUNC) ? skb->len : size; + +out_err: skb_free_datagram(sk, skb); =20 - return size; + return ret; } =20 static int isotp_release(struct socket *sock) @@ -1104,6 +1111,7 @@ static int isotp_bind(struct socket *sock, struct soc= kaddr *uaddr, int len) struct net *net =3D sock_net(sk); int ifindex; struct net_device *dev; + canid_t tx_id, rx_id; int err =3D 0; int notify_enetdown =3D 0; int do_rx_reg =3D 1; @@ -1111,8 +1119,18 @@ static int isotp_bind(struct socket *sock, struct so= ckaddr *uaddr, int len) if (len < ISOTP_MIN_NAMELEN) return -EINVAL; =20 - if (addr->can_addr.tp.tx_id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) - return -EADDRNOTAVAIL; + /* sanitize tx/rx CAN identifiers */ + tx_id =3D addr->can_addr.tp.tx_id; + if (tx_id & CAN_EFF_FLAG) + tx_id &=3D (CAN_EFF_FLAG | CAN_EFF_MASK); + else + tx_id &=3D CAN_SFF_MASK; + + rx_id =3D addr->can_addr.tp.rx_id; + if (rx_id & CAN_EFF_FLAG) + rx_id &=3D (CAN_EFF_FLAG | CAN_EFF_MASK); + else + rx_id &=3D CAN_SFF_MASK; =20 if (!addr->can_ifindex) return -ENODEV; @@ -1124,21 +1142,13 @@ static int isotp_bind(struct socket *sock, struct s= ockaddr *uaddr, int len) do_rx_reg =3D 0; =20 /* do not validate rx address for functional addressing */ - if (do_rx_reg) { - if (addr->can_addr.tp.rx_id =3D=3D addr->can_addr.tp.tx_id) { - err =3D -EADDRNOTAVAIL; - goto out; - } - - if (addr->can_addr.tp.rx_id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) { - err =3D -EADDRNOTAVAIL; - goto out; - } + if (do_rx_reg && rx_id =3D=3D tx_id) { + err =3D -EADDRNOTAVAIL; + goto out; } =20 if (so->bound && addr->can_ifindex =3D=3D so->ifindex && - addr->can_addr.tp.rx_id =3D=3D so->rxid && - addr->can_addr.tp.tx_id =3D=3D so->txid) + rx_id =3D=3D so->rxid && tx_id =3D=3D so->txid) goto out; =20 dev =3D dev_get_by_index(net, addr->can_ifindex); @@ -1162,8 +1172,7 @@ static int isotp_bind(struct socket *sock, struct soc= kaddr *uaddr, int len) ifindex =3D dev->ifindex; =20 if (do_rx_reg) - can_rx_register(net, dev, addr->can_addr.tp.rx_id, - SINGLE_MASK(addr->can_addr.tp.rx_id), + can_rx_register(net, dev, rx_id, SINGLE_MASK(rx_id), isotp_rcv, sk, "isotp", sk); =20 dev_put(dev); @@ -1183,8 +1192,8 @@ static int isotp_bind(struct socket *sock, struct soc= kaddr *uaddr, int len) =20 /* switch to new settings */ so->ifindex =3D ifindex; - so->rxid =3D addr->can_addr.tp.rx_id; - so->txid =3D addr->can_addr.tp.tx_id; + so->rxid =3D rx_id; + so->txid =3D tx_id; so->bound =3D 1; =20 out: diff --git a/net/core/skbuff.c b/net/core/skbuff.c index f1e3d70e8987..fdd804120600 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -201,7 +201,7 @@ static void __build_skb_around(struct sk_buff *skb, voi= d *data, skb->head =3D data; skb->data =3D data; skb_reset_tail_pointer(skb); - skb->end =3D skb->tail + size; + skb_set_end_offset(skb, size); skb->mac_header =3D (typeof(skb->mac_header))~0U; skb->transport_header =3D (typeof(skb->transport_header))~0U; =20 @@ -1738,11 +1738,10 @@ int pskb_expand_head(struct sk_buff *skb, int nhead= , int ntail, skb->head =3D data; skb->head_frag =3D 0; skb->data +=3D off; + + skb_set_end_offset(skb, size); #ifdef NET_SKBUFF_DATA_USES_OFFSET - skb->end =3D size; off =3D nhead; -#else - skb->end =3D skb->head + size; #endif skb->tail +=3D off; skb_headers_offset_update(skb, nhead); @@ -1790,6 +1789,38 @@ struct sk_buff *skb_realloc_headroom(struct sk_buff = *skb, unsigned int headroom) } EXPORT_SYMBOL(skb_realloc_headroom); =20 +int __skb_unclone_keeptruesize(struct sk_buff *skb, gfp_t pri) +{ + unsigned int saved_end_offset, saved_truesize; + struct skb_shared_info *shinfo; + int res; + + saved_end_offset =3D skb_end_offset(skb); + saved_truesize =3D skb->truesize; + + res =3D pskb_expand_head(skb, 0, 0, pri); + if (res) + return res; + + skb->truesize =3D saved_truesize; + + if (likely(skb_end_offset(skb) =3D=3D saved_end_offset)) + return 0; + + shinfo =3D skb_shinfo(skb); + + /* We are about to change back skb->end, + * we need to move skb_shinfo() to its new location. + */ + memmove(skb->head + saved_end_offset, + shinfo, + offsetof(struct skb_shared_info, frags[shinfo->nr_frags])); + + skb_set_end_offset(skb, saved_end_offset); + + return 0; +} + /** * skb_expand_head - reallocate header of &sk_buff * @skb: buffer to reallocate @@ -6138,11 +6169,7 @@ static int pskb_carve_inside_header(struct sk_buff *= skb, const u32 off, skb->head =3D data; skb->data =3D data; skb->head_frag =3D 0; -#ifdef NET_SKBUFF_DATA_USES_OFFSET - skb->end =3D size; -#else - skb->end =3D skb->head + size; -#endif + skb_set_end_offset(skb, size); skb_set_tail_pointer(skb, skb_headlen(skb)); skb_headers_offset_update(skb, 0); skb->cloned =3D 0; @@ -6280,11 +6307,7 @@ static int pskb_carve_inside_nonlinear(struct sk_buf= f *skb, const u32 off, skb->head =3D data; skb->head_frag =3D 0; skb->data =3D data; -#ifdef NET_SKBUFF_DATA_USES_OFFSET - skb->end =3D size; -#else - skb->end =3D skb->head + size; -#endif + skb_set_end_offset(skb, size); skb_reset_tail_pointer(skb); skb_headers_offset_update(skb, 0); skb->cloned =3D 0; diff --git a/net/core/skmsg.c b/net/core/skmsg.c index 929a2b096b04..cc381165ea08 100644 --- a/net/core/skmsg.c +++ b/net/core/skmsg.c @@ -27,6 +27,7 @@ int sk_msg_alloc(struct sock *sk, struct sk_msg *msg, int= len, int elem_first_coalesce) { struct page_frag *pfrag =3D sk_page_frag(sk); + u32 osize =3D msg->sg.size; int ret =3D 0; =20 len -=3D msg->sg.size; @@ -35,13 +36,17 @@ int sk_msg_alloc(struct sock *sk, struct sk_msg *msg, i= nt len, u32 orig_offset; int use, i; =20 - if (!sk_page_frag_refill(sk, pfrag)) - return -ENOMEM; + if (!sk_page_frag_refill(sk, pfrag)) { + ret =3D -ENOMEM; + goto msg_trim; + } =20 orig_offset =3D pfrag->offset; use =3D min_t(int, len, pfrag->size - orig_offset); - if (!sk_wmem_schedule(sk, use)) - return -ENOMEM; + if (!sk_wmem_schedule(sk, use)) { + ret =3D -ENOMEM; + goto msg_trim; + } =20 i =3D msg->sg.end; sk_msg_iter_var_prev(i); @@ -71,6 +76,10 @@ int sk_msg_alloc(struct sock *sk, struct sk_msg *msg, in= t len, } =20 return ret; + +msg_trim: + sk_msg_trim(sk, msg, osize); + return ret; } EXPORT_SYMBOL_GPL(sk_msg_alloc); =20 diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index e64ef196a984..ff29a5a3e4c1 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -1613,6 +1613,10 @@ void dsa_switch_shutdown(struct dsa_switch *ds) struct dsa_port *dp; =20 mutex_lock(&dsa2_mutex); + + if (!ds->setup) + goto out; + rtnl_lock(); =20 dsa_switch_for_each_user_port(dp, ds) { @@ -1629,6 +1633,7 @@ void dsa_switch_shutdown(struct dsa_switch *ds) dp->master->dsa_ptr =3D NULL; =20 rtnl_unlock(); +out: mutex_unlock(&dsa2_mutex); } EXPORT_SYMBOL_GPL(dsa_switch_shutdown); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 2c30c599cc16..750e229b7c49 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -498,6 +498,15 @@ void __ip_select_ident(struct net *net, struct iphdr *= iph, int segs) } EXPORT_SYMBOL(__ip_select_ident); =20 +static void ip_rt_fix_tos(struct flowi4 *fl4) +{ + __u8 tos =3D RT_FL_TOS(fl4); + + fl4->flowi4_tos =3D tos & IPTOS_RT_MASK; + fl4->flowi4_scope =3D tos & RTO_ONLINK ? + RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; +} + static void __build_flow_key(const struct net *net, struct flowi4 *fl4, const struct sock *sk, const struct iphdr *iph, @@ -823,6 +832,7 @@ static void ip_do_redirect(struct dst_entry *dst, struc= t sock *sk, struct sk_buf rt =3D (struct rtable *) dst; =20 __build_flow_key(net, &fl4, sk, iph, oif, tos, prot, mark, 0); + ip_rt_fix_tos(&fl4); __ip_do_redirect(rt, skb, &fl4, true); } =20 @@ -1047,6 +1057,7 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, = struct sock *sk, struct flowi4 fl4; =20 ip_rt_build_flow_key(&fl4, sk, skb); + ip_rt_fix_tos(&fl4); =20 /* Don't make lookup fail for bridged encapsulations */ if (skb && netif_is_any_bridge_port(skb->dev)) @@ -1121,6 +1132,8 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct = sock *sk, u32 mtu) goto out; =20 new =3D true; + } else { + ip_rt_fix_tos(&fl4); } =20 __ip_rt_update_pmtu((struct rtable *)xfrm_dst_path(&rt->dst), &fl4, mtu); @@ -2601,7 +2614,6 @@ static struct rtable *__mkroute_output(const struct f= ib_result *res, struct rtable *ip_route_output_key_hash(struct net *net, struct flowi4 *fl= 4, const struct sk_buff *skb) { - __u8 tos =3D RT_FL_TOS(fl4); struct fib_result res =3D { .type =3D RTN_UNSPEC, .fi =3D NULL, @@ -2611,9 +2623,7 @@ struct rtable *ip_route_output_key_hash(struct net *n= et, struct flowi4 *fl4, struct rtable *rth; =20 fl4->flowi4_iif =3D LOOPBACK_IFINDEX; - fl4->flowi4_tos =3D tos & IPTOS_RT_MASK; - fl4->flowi4_scope =3D ((tos & RTO_ONLINK) ? - RT_SCOPE_LINK : RT_SCOPE_UNIVERSE); + ip_rt_fix_tos(fl4); =20 rcu_read_lock(); rth =3D ip_route_output_key_hash_rcu(net, fl4, &res, skb); diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c index 9b9b02052fd3..1cdcb4df0eb7 100644 --- a/net/ipv4/tcp_bpf.c +++ b/net/ipv4/tcp_bpf.c @@ -138,10 +138,9 @@ int tcp_bpf_sendmsg_redir(struct sock *sk, struct sk_m= sg *msg, struct sk_psock *psock =3D sk_psock_get(sk); int ret; =20 - if (unlikely(!psock)) { - sk_msg_free(sk, msg); - return 0; - } + if (unlikely(!psock)) + return -EPIPE; + ret =3D ingress ? bpf_tcp_ingress(sk, psock, msg, bytes, flags) : tcp_bpf_push_locked(sk, msg, bytes, flags, false); sk_psock_put(sk, psock); @@ -335,7 +334,7 @@ static int tcp_bpf_send_verdict(struct sock *sk, struct= sk_psock *psock, cork =3D true; psock->cork =3D NULL; } - sk_msg_return(sk, msg, tosend); + sk_msg_return(sk, msg, msg->sg.size); release_sock(sk); =20 ret =3D tcp_bpf_sendmsg_redir(sk_redir, msg, tosend, flags); @@ -375,8 +374,11 @@ static int tcp_bpf_send_verdict(struct sock *sk, struc= t sk_psock *psock, } if (msg && msg->sg.data[msg->sg.start].page_link && - msg->sg.data[msg->sg.start].length) + msg->sg.data[msg->sg.start].length) { + if (eval =3D=3D __SK_REDIRECT) + sk_mem_charge(sk, msg->sg.size); goto more_data; + } } return ret; } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 2e6e5a70168e..3a8126dfcd4d 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -3719,6 +3719,7 @@ static void tcp_connect_queue_skb(struct sock *sk, st= ruct sk_buff *skb) */ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) { + struct inet_connection_sock *icsk =3D inet_csk(sk); struct tcp_sock *tp =3D tcp_sk(sk); struct tcp_fastopen_request *fo =3D tp->fastopen_req; int space, err =3D 0; @@ -3733,8 +3734,10 @@ static int tcp_send_syn_data(struct sock *sk, struct= sk_buff *syn) * private TCP options. The cost is reduced data space in SYN :( */ tp->rx_opt.mss_clamp =3D tcp_mss_clamp(tp, tp->rx_opt.mss_clamp); + /* Sync mss_cache after updating the mss_clamp */ + tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); =20 - space =3D __tcp_mtu_to_mss(sk, inet_csk(sk)->icsk_pmtu_cookie) - + space =3D __tcp_mtu_to_mss(sk, icsk->icsk_pmtu_cookie) - MAX_TCP_OPTION_SPACE; =20 space =3D min_t(size_t, space, fo->size); diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index d0d280077721..ad07904642ca 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -45,6 +45,19 @@ static int __xfrm6_output_finish(struct net *net, struct= sock *sk, struct sk_buf return xfrm_output(sk, skb); } =20 +static int xfrm6_noneed_fragment(struct sk_buff *skb) +{ + struct frag_hdr *fh; + u8 prevhdr =3D ipv6_hdr(skb)->nexthdr; + + if (prevhdr !=3D NEXTHDR_FRAGMENT) + return 0; + fh =3D (struct frag_hdr *)(skb->data + sizeof(struct ipv6hdr)); + if (fh->nexthdr =3D=3D NEXTHDR_ESP || fh->nexthdr =3D=3D NEXTHDR_AUTH) + return 1; + return 0; +} + static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff= *skb) { struct dst_entry *dst =3D skb_dst(skb); @@ -73,6 +86,9 @@ static int __xfrm6_output(struct net *net, struct sock *s= k, struct sk_buff *skb) xfrm6_local_rxpmtu(skb, mtu); kfree_skb(skb); return -EMSGSIZE; + } else if (toobig && xfrm6_noneed_fragment(skb)) { + skb->ignore_df =3D 1; + goto skip_frag; } else if (!skb->ignore_df && toobig && skb->sk) { xfrm_local_error(skb, mtu); kfree_skb(skb); diff --git a/net/key/af_key.c b/net/key/af_key.c index 9bf52a09b5ff..fd51db3be91c 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1699,7 +1699,7 @@ static int pfkey_register(struct sock *sk, struct sk_= buff *skb, const struct sad =20 xfrm_probe_algs(); =20 - supp_skb =3D compose_sadb_supported(hdr, GFP_KERNEL); + supp_skb =3D compose_sadb_supported(hdr, GFP_KERNEL | __GFP_ZERO); if (!supp_skb) { if (hdr->sadb_msg_satype !=3D SADB_SATYPE_UNSPEC) pfk->registered &=3D ~(1<sadb_msg_satype); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3354a3b905b8..541723babcf0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2380,7 +2380,7 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80= 211_sta_vht_cap *vht_cap, u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht= _cap, const struct cfg80211_chan_def *chandef); u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata, u8 iftype); -u8 *ieee80211_ie_build_he_cap(u8 *pos, +u8 *ieee80211_ie_build_he_cap(u32 disable_flags, u8 *pos, const struct ieee80211_sta_he_cap *he_cap, u8 *end); void ieee80211_ie_build_he_6ghz_cap(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 45fb517591ee..5311c3cd3050 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1131,17 +1131,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) local->scan_ies_len +=3D 2 + sizeof(struct ieee80211_vht_cap); =20 - /* HE cap element is variable in size - set len to allow max size */ /* - * TODO: 1 is added at the end of the calculation to accommodate for - * the temporary placing of the HE capabilities IE under EXT. - * Remove it once it is placed in the final place. - */ - if (supp_he) + * HE cap element is variable in size - set len to allow max size */ + if (supp_he) { local->scan_ies_len +=3D - 2 + sizeof(struct ieee80211_he_cap_elem) + + 3 + sizeof(struct ieee80211_he_cap_elem) + sizeof(struct ieee80211_he_mcs_nss_supp) + - IEEE80211_HE_PPE_THRES_MAX_LEN + 1; + IEEE80211_HE_PPE_THRES_MAX_LEN; + } =20 if (!local->ops->hw_scan) { /* For hw_scan, driver needs to set these up. */ diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 15ac08d111ea..6847fdf93439 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -580,7 +580,7 @@ int mesh_add_he_cap_ie(struct ieee80211_sub_if_data *sd= ata, return -ENOMEM; =20 pos =3D skb_put(skb, ie_len); - ieee80211_ie_build_he_cap(pos, he_cap, pos + ie_len); + ieee80211_ie_build_he_cap(0, pos, he_cap, pos + ie_len); =20 return 0; } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 404b84650161..ce56f23a4a1f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -630,7 +630,7 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if= _data *sdata, struct sk_buff *skb, struct ieee80211_supported_band *sband) { - u8 *pos; + u8 *pos, *pre_he_pos; const struct ieee80211_sta_he_cap *he_cap =3D NULL; struct ieee80211_chanctx_conf *chanctx_conf; u8 he_cap_size; @@ -647,20 +647,21 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_= if_data *sdata, =20 he_cap =3D ieee80211_get_he_iftype_cap(sband, ieee80211_vif_type_p2p(&sdata->vif)); - if (!he_cap || !reg_cap) + if (!he_cap || !chanctx_conf || !reg_cap) return; =20 - /* - * TODO: the 1 added is because this temporarily is under the EXTENSION - * IE. Get rid of it when it moves. - */ + /* get a max size estimate */ he_cap_size =3D 2 + 1 + sizeof(he_cap->he_cap_elem) + ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem) + ieee80211_he_ppe_size(he_cap->ppe_thres[0], he_cap->he_cap_elem.phy_cap_info); pos =3D skb_put(skb, he_cap_size); - ieee80211_ie_build_he_cap(pos, he_cap, pos + he_cap_size); + pre_he_pos =3D pos; + pos =3D ieee80211_ie_build_he_cap(sdata->u.mgd.flags, + pos, he_cap, pos + he_cap_size); + /* trim excess if any */ + skb_trim(skb, skb->len - (pre_he_pos + he_cap_size - pos)); =20 ieee80211_ie_build_he_6ghz_cap(sdata, skb); } diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 0e4e1956bcea..49a9bbb12538 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1961,7 +1961,7 @@ static int ieee80211_build_preq_ies_band(struct ieee8= 0211_sub_if_data *sdata, if (he_cap && cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band), IEEE80211_CHAN_NO_HE)) { - pos =3D ieee80211_ie_build_he_cap(pos, he_cap, end); + pos =3D ieee80211_ie_build_he_cap(0, pos, he_cap, end); if (!pos) goto out_err; } @@ -2905,10 +2905,11 @@ u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_= data *sdata, u8 iftype) he_cap->he_cap_elem.phy_cap_info); } =20 -u8 *ieee80211_ie_build_he_cap(u8 *pos, +u8 *ieee80211_ie_build_he_cap(u32 disable_flags, u8 *pos, const struct ieee80211_sta_he_cap *he_cap, u8 *end) { + struct ieee80211_he_cap_elem elem; u8 n; u8 ie_len; u8 *orig_pos =3D pos; @@ -2921,7 +2922,23 @@ u8 *ieee80211_ie_build_he_cap(u8 *pos, if (!he_cap) return orig_pos; =20 - n =3D ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem); + /* modify on stack first to calculate 'n' and 'ie_len' correctly */ + elem =3D he_cap->he_cap_elem; + + if (disable_flags & IEEE80211_STA_DISABLE_40MHZ) + elem.phy_cap_info[0] &=3D + ~(IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G); + + if (disable_flags & IEEE80211_STA_DISABLE_160MHZ) + elem.phy_cap_info[0] &=3D + ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + + if (disable_flags & IEEE80211_STA_DISABLE_80P80MHZ) + elem.phy_cap_info[0] &=3D + ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G; + + n =3D ieee80211_he_mcs_nss_size(&elem); ie_len =3D 2 + 1 + sizeof(he_cap->he_cap_elem) + n + ieee80211_he_ppe_size(he_cap->ppe_thres[0], @@ -2935,8 +2952,8 @@ u8 *ieee80211_ie_build_he_cap(u8 *pos, *pos++ =3D WLAN_EID_EXT_HE_CAPABILITY; =20 /* Fixed data */ - memcpy(pos, &he_cap->he_cap_elem, sizeof(he_cap->he_cap_elem)); - pos +=3D sizeof(he_cap->he_cap_elem); + memcpy(pos, &elem, sizeof(elem)); + pos +=3D sizeof(elem); =20 memcpy(pos, &he_cap->he_mcs_nss_supp, n); pos +=3D n; diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 7566c9dc6681..1784e528704a 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -1202,6 +1202,7 @@ static struct sk_buff *__mptcp_alloc_tx_skb(struct so= ck *sk, struct sock *ssk, g tcp_skb_entail(ssk, skb); return skb; } + tcp_skb_tsorted_anchor_cleanup(skb); kfree_skb(skb); return NULL; } diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack= _core.c index 7f7997460764..917e708a4561 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -989,7 +989,7 @@ static int __nf_ct_resolve_clash(struct sk_buff *skb, =20 nf_ct_acct_merge(ct, ctinfo, loser_ct); nf_ct_add_to_dying_list(loser_ct); - nf_conntrack_put(&loser_ct->ct_general); + nf_ct_put(loser_ct); nf_ct_set(skb, ct, ctinfo); =20 NF_CT_STAT_INC(net, clash_resolve); @@ -1920,7 +1920,7 @@ nf_conntrack_in(struct sk_buff *skb, const struct nf_= hook_state *state) /* Invalid: inverse of the return code tells * the netfilter core what to do */ pr_debug("nf_conntrack_in: Can't track with proto module\n"); - nf_conntrack_put(&ct->ct_general); + nf_ct_put(ct); skb->_nfct =3D 0; /* Special case: TCP tracker reports an attempt to reopen a * closed/aborted connection. We have to go back and create a diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntra= ck_helper.c index ae4488a13c70..ceb38a7b37cb 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -556,6 +556,12 @@ static const struct nf_ct_ext_type helper_extend =3D { .id =3D NF_CT_EXT_HELPER, }; =20 +void nf_ct_set_auto_assign_helper_warned(struct net *net) +{ + nf_ct_pernet(net)->auto_assign_helper_warned =3D true; +} +EXPORT_SYMBOL_GPL(nf_ct_set_auto_assign_helper_warned); + void nf_conntrack_helper_pernet_init(struct net *net) { struct nf_conntrack_net *cnet =3D nf_ct_pernet(net); diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conn= track_proto_tcp.c index af5115e127cf..3cee5d8ee702 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -341,8 +341,8 @@ static void tcp_options(const struct sk_buff *skb, if (!ptr) return; =20 - state->td_scale =3D - state->flags =3D 0; + state->td_scale =3D 0; + state->flags &=3D IP_CT_TCP_FLAG_BE_LIBERAL; =20 while (length > 0) { int opcode=3D*ptr++; @@ -839,6 +839,16 @@ static bool tcp_can_early_drop(const struct nf_conn *c= t) return false; } =20 +static void nf_ct_tcp_state_reset(struct ip_ct_tcp_state *state) +{ + state->td_end =3D 0; + state->td_maxend =3D 0; + state->td_maxwin =3D 0; + state->td_maxack =3D 0; + state->td_scale =3D 0; + state->flags &=3D IP_CT_TCP_FLAG_BE_LIBERAL; +} + /* Returns verdict for packet, or -1 for invalid. */ int nf_conntrack_tcp_packet(struct nf_conn *ct, struct sk_buff *skb, @@ -945,8 +955,7 @@ int nf_conntrack_tcp_packet(struct nf_conn *ct, ct->proto.tcp.last_flags &=3D ~IP_CT_EXP_CHALLENGE_ACK; ct->proto.tcp.seen[ct->proto.tcp.last_dir].flags =3D ct->proto.tcp.last_flags; - memset(&ct->proto.tcp.seen[dir], 0, - sizeof(struct ip_ct_tcp_state)); + nf_ct_tcp_state_reset(&ct->proto.tcp.seen[dir]); break; } ct->proto.tcp.last_index =3D index; diff --git a/net/netfilter/nf_flow_table_inet.c b/net/netfilter/nf_flow_tab= le_inet.c index bc4126d8ef65..280fdd32965f 100644 --- a/net/netfilter/nf_flow_table_inet.c +++ b/net/netfilter/nf_flow_table_inet.c @@ -6,12 +6,29 @@ #include #include #include +#include =20 static unsigned int nf_flow_offload_inet_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) { + struct vlan_ethhdr *veth; + __be16 proto; + switch (skb->protocol) { + case htons(ETH_P_8021Q): + veth =3D (struct vlan_ethhdr *)skb_mac_header(skb); + proto =3D veth->h_vlan_encapsulated_proto; + break; + case htons(ETH_P_PPP_SES): + proto =3D nf_flow_pppoe_proto(skb); + break; + default: + proto =3D skb->protocol; + break; + } + + switch (proto) { case htons(ETH_P_IP): return nf_flow_offload_ip_hook(priv, skb, state); case htons(ETH_P_IPV6): diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table= _ip.c index 889cf88d3dba..6257d87c3a56 100644 --- a/net/netfilter/nf_flow_table_ip.c +++ b/net/netfilter/nf_flow_table_ip.c @@ -8,8 +8,6 @@ #include #include #include -#include -#include #include #include #include @@ -239,22 +237,6 @@ static unsigned int nf_flow_xmit_xfrm(struct sk_buff *= skb, return NF_STOLEN; } =20 -static inline __be16 nf_flow_pppoe_proto(const struct sk_buff *skb) -{ - __be16 proto; - - proto =3D *((__be16 *)(skb_mac_header(skb) + ETH_HLEN + - sizeof(struct pppoe_hdr))); - switch (proto) { - case htons(PPP_IP): - return htons(ETH_P_IP); - case htons(PPP_IPV6): - return htons(ETH_P_IPV6); - } - - return 0; -} - static bool nf_flow_skb_encap_protocol(const struct sk_buff *skb, __be16 p= roto, u32 *offset) { diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c index 99b1de14ff7e..54ecb9fbf2de 100644 --- a/net/netfilter/nft_ct.c +++ b/net/netfilter/nft_ct.c @@ -1040,6 +1040,9 @@ static int nft_ct_helper_obj_init(const struct nft_ct= x *ctx, if (err < 0) goto err_put_helper; =20 + /* Avoid the bogus warning, helper will be assigned after CT init */ + nf_ct_set_auto_assign_helper_warned(ctx->net); + return 0; =20 err_put_helper: diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 9eba2e648385..6fbc3ea735e5 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -157,6 +157,8 @@ EXPORT_SYMBOL(do_trace_netlink_extack); =20 static inline u32 netlink_group_mask(u32 group) { + if (group > 32) + return 0; return group ? 1 << (group - 1) : 0; } =20 diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index 1b5eae57bc90..f2b64cab9af7 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c @@ -574,7 +574,7 @@ ovs_ct_expect_find(struct net *net, const struct nf_con= ntrack_zone *zone, struct nf_conn *ct =3D nf_ct_tuplehash_to_ctrack(h); =20 nf_ct_delete(ct, 0, 0); - nf_conntrack_put(&ct->ct_general); + nf_ct_put(ct); } } =20 @@ -723,7 +723,7 @@ static bool skb_nfct_cached(struct net *net, if (nf_ct_is_confirmed(ct)) nf_ct_delete(ct, 0, 0); =20 - nf_conntrack_put(&ct->ct_general); + nf_ct_put(ct); nf_ct_set(skb, NULL, 0); return false; } @@ -732,6 +732,57 @@ static bool skb_nfct_cached(struct net *net, } =20 #if IS_ENABLED(CONFIG_NF_NAT) +static void ovs_nat_update_key(struct sw_flow_key *key, + const struct sk_buff *skb, + enum nf_nat_manip_type maniptype) +{ + if (maniptype =3D=3D NF_NAT_MANIP_SRC) { + __be16 src; + + key->ct_state |=3D OVS_CS_F_SRC_NAT; + if (key->eth.type =3D=3D htons(ETH_P_IP)) + key->ipv4.addr.src =3D ip_hdr(skb)->saddr; + else if (key->eth.type =3D=3D htons(ETH_P_IPV6)) + memcpy(&key->ipv6.addr.src, &ipv6_hdr(skb)->saddr, + sizeof(key->ipv6.addr.src)); + else + return; + + if (key->ip.proto =3D=3D IPPROTO_UDP) + src =3D udp_hdr(skb)->source; + else if (key->ip.proto =3D=3D IPPROTO_TCP) + src =3D tcp_hdr(skb)->source; + else if (key->ip.proto =3D=3D IPPROTO_SCTP) + src =3D sctp_hdr(skb)->source; + else + return; + + key->tp.src =3D src; + } else { + __be16 dst; + + key->ct_state |=3D OVS_CS_F_DST_NAT; + if (key->eth.type =3D=3D htons(ETH_P_IP)) + key->ipv4.addr.dst =3D ip_hdr(skb)->daddr; + else if (key->eth.type =3D=3D htons(ETH_P_IPV6)) + memcpy(&key->ipv6.addr.dst, &ipv6_hdr(skb)->daddr, + sizeof(key->ipv6.addr.dst)); + else + return; + + if (key->ip.proto =3D=3D IPPROTO_UDP) + dst =3D udp_hdr(skb)->dest; + else if (key->ip.proto =3D=3D IPPROTO_TCP) + dst =3D tcp_hdr(skb)->dest; + else if (key->ip.proto =3D=3D IPPROTO_SCTP) + dst =3D sctp_hdr(skb)->dest; + else + return; + + key->tp.dst =3D dst; + } +} + /* Modelled after nf_nat_ipv[46]_fn(). * range is only used for new, uninitialized NAT state. * Returns either NF_ACCEPT or NF_DROP. @@ -739,7 +790,7 @@ static bool skb_nfct_cached(struct net *net, static int ovs_ct_nat_execute(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo, const struct nf_nat_range2 *range, - enum nf_nat_manip_type maniptype) + enum nf_nat_manip_type maniptype, struct sw_flow_key *key) { int hooknum, nh_off, err =3D NF_ACCEPT; =20 @@ -811,58 +862,11 @@ static int ovs_ct_nat_execute(struct sk_buff *skb, st= ruct nf_conn *ct, push: skb_push_rcsum(skb, nh_off); =20 - return err; -} - -static void ovs_nat_update_key(struct sw_flow_key *key, - const struct sk_buff *skb, - enum nf_nat_manip_type maniptype) -{ - if (maniptype =3D=3D NF_NAT_MANIP_SRC) { - __be16 src; - - key->ct_state |=3D OVS_CS_F_SRC_NAT; - if (key->eth.type =3D=3D htons(ETH_P_IP)) - key->ipv4.addr.src =3D ip_hdr(skb)->saddr; - else if (key->eth.type =3D=3D htons(ETH_P_IPV6)) - memcpy(&key->ipv6.addr.src, &ipv6_hdr(skb)->saddr, - sizeof(key->ipv6.addr.src)); - else - return; - - if (key->ip.proto =3D=3D IPPROTO_UDP) - src =3D udp_hdr(skb)->source; - else if (key->ip.proto =3D=3D IPPROTO_TCP) - src =3D tcp_hdr(skb)->source; - else if (key->ip.proto =3D=3D IPPROTO_SCTP) - src =3D sctp_hdr(skb)->source; - else - return; - - key->tp.src =3D src; - } else { - __be16 dst; - - key->ct_state |=3D OVS_CS_F_DST_NAT; - if (key->eth.type =3D=3D htons(ETH_P_IP)) - key->ipv4.addr.dst =3D ip_hdr(skb)->daddr; - else if (key->eth.type =3D=3D htons(ETH_P_IPV6)) - memcpy(&key->ipv6.addr.dst, &ipv6_hdr(skb)->daddr, - sizeof(key->ipv6.addr.dst)); - else - return; - - if (key->ip.proto =3D=3D IPPROTO_UDP) - dst =3D udp_hdr(skb)->dest; - else if (key->ip.proto =3D=3D IPPROTO_TCP) - dst =3D tcp_hdr(skb)->dest; - else if (key->ip.proto =3D=3D IPPROTO_SCTP) - dst =3D sctp_hdr(skb)->dest; - else - return; + /* Update the flow key if NAT successful. */ + if (err =3D=3D NF_ACCEPT) + ovs_nat_update_key(key, skb, maniptype); =20 - key->tp.dst =3D dst; - } + return err; } =20 /* Returns NF_DROP if the packet should be dropped, NF_ACCEPT otherwise. */ @@ -904,7 +908,7 @@ static int ovs_ct_nat(struct net *net, struct sw_flow_k= ey *key, } else { return NF_ACCEPT; /* Connection is not NATed. */ } - err =3D ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, maniptype); + err =3D ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, maniptype, key); =20 if (err =3D=3D NF_ACCEPT && ct->status & IPS_DST_NAT) { if (ct->status & IPS_SRC_NAT) { @@ -914,17 +918,13 @@ static int ovs_ct_nat(struct net *net, struct sw_flow= _key *key, maniptype =3D NF_NAT_MANIP_SRC; =20 err =3D ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, - maniptype); + maniptype, key); } else if (CTINFO2DIR(ctinfo) =3D=3D IP_CT_DIR_ORIGINAL) { err =3D ovs_ct_nat_execute(skb, ct, ctinfo, NULL, - NF_NAT_MANIP_SRC); + NF_NAT_MANIP_SRC, key); } } =20 - /* Mark NAT done if successful and update the flow key. */ - if (err =3D=3D NF_ACCEPT) - ovs_nat_update_key(key, skb, maniptype); - return err; } #else /* !CONFIG_NF_NAT */ @@ -967,7 +967,8 @@ static int __ovs_ct_lookup(struct net *net, struct sw_f= low_key *key, =20 /* Associate skb with specified zone. */ if (tmpl) { - nf_conntrack_put(skb_nfct(skb)); + ct =3D nf_ct_get(skb, &ctinfo); + nf_ct_put(ct); nf_conntrack_get(&tmpl->ct_general); nf_ct_set(skb, tmpl, IP_CT_NEW); } @@ -1328,7 +1329,12 @@ int ovs_ct_execute(struct net *net, struct sk_buff *= skb, =20 int ovs_ct_clear(struct sk_buff *skb, struct sw_flow_key *key) { - nf_conntrack_put(skb_nfct(skb)); + enum ip_conntrack_info ctinfo; + struct nf_conn *ct; + + ct =3D nf_ct_get(skb, &ctinfo); + + nf_ct_put(ct); nf_ct_set(skb, NULL, IP_CT_UNTRACKED); ovs_ct_fill_key(skb, key, false); =20 diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index fd1f809e9bc1..0d677c9c2c80 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -2201,8 +2201,8 @@ static int __ovs_nla_put_key(const struct sw_flow_key= *swkey, icmpv6_key->icmpv6_type =3D ntohs(output->tp.src); icmpv6_key->icmpv6_code =3D ntohs(output->tp.dst); =20 - if (icmpv6_key->icmpv6_type =3D=3D NDISC_NEIGHBOUR_SOLICITATION || - icmpv6_key->icmpv6_type =3D=3D NDISC_NEIGHBOUR_ADVERTISEMENT) { + if (swkey->tp.src =3D=3D htons(NDISC_NEIGHBOUR_SOLICITATION) || + swkey->tp.src =3D=3D htons(NDISC_NEIGHBOUR_ADVERTISEMENT)) { struct ovs_key_nd *nd_key; =20 nla =3D nla_reserve(skb, OVS_KEY_ATTR_ND, sizeof(*nd_key)); diff --git a/net/rfkill/core.c b/net/rfkill/core.c index ac15a944573f..068c7bcd30c9 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -78,6 +78,7 @@ struct rfkill_data { struct mutex mtx; wait_queue_head_t read_wait; bool input_handler; + u8 max_size; }; =20 =20 @@ -1141,6 +1142,8 @@ static int rfkill_fop_open(struct inode *inode, struc= t file *file) if (!data) return -ENOMEM; =20 + data->max_size =3D RFKILL_EVENT_SIZE_V1; + INIT_LIST_HEAD(&data->events); mutex_init(&data->mtx); init_waitqueue_head(&data->read_wait); @@ -1223,6 +1226,7 @@ static ssize_t rfkill_fop_read(struct file *file, cha= r __user *buf, list); =20 sz =3D min_t(unsigned long, sizeof(ev->ev), count); + sz =3D min_t(unsigned long, sz, data->max_size); ret =3D sz; if (copy_to_user(buf, &ev->ev, sz)) ret =3D -EFAULT; @@ -1237,6 +1241,7 @@ static ssize_t rfkill_fop_read(struct file *file, cha= r __user *buf, static ssize_t rfkill_fop_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { + struct rfkill_data *data =3D file->private_data; struct rfkill *rfkill; struct rfkill_event_ext ev; int ret; @@ -1251,6 +1256,7 @@ static ssize_t rfkill_fop_write(struct file *file, co= nst char __user *buf, * our API version even in a write() call, if it cares. */ count =3D min(count, sizeof(ev)); + count =3D min_t(size_t, count, data->max_size); if (copy_from_user(&ev, buf, count)) return -EFAULT; =20 @@ -1310,31 +1316,47 @@ static int rfkill_fop_release(struct inode *inode, = struct file *file) return 0; } =20 -#ifdef CONFIG_RFKILL_INPUT static long rfkill_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct rfkill_data *data =3D file->private_data; + int ret =3D -ENOSYS; + u32 size; =20 if (_IOC_TYPE(cmd) !=3D RFKILL_IOC_MAGIC) return -ENOSYS; =20 - if (_IOC_NR(cmd) !=3D RFKILL_IOC_NOINPUT) - return -ENOSYS; - mutex_lock(&data->mtx); - - if (!data->input_handler) { - if (atomic_inc_return(&rfkill_input_disabled) =3D=3D 1) - printk(KERN_DEBUG "rfkill: input handler disabled\n"); - data->input_handler =3D true; + switch (_IOC_NR(cmd)) { +#ifdef CONFIG_RFKILL_INPUT + case RFKILL_IOC_NOINPUT: + if (!data->input_handler) { + if (atomic_inc_return(&rfkill_input_disabled) =3D=3D 1) + printk(KERN_DEBUG "rfkill: input handler disabled\n"); + data->input_handler =3D true; + } + ret =3D 0; + break; +#endif + case RFKILL_IOC_MAX_SIZE: + if (get_user(size, (__u32 __user *)arg)) { + ret =3D -EFAULT; + break; + } + if (size < RFKILL_EVENT_SIZE_V1 || size > U8_MAX) { + ret =3D -EINVAL; + break; + } + data->max_size =3D size; + ret =3D 0; + break; + default: + break; } - mutex_unlock(&data->mtx); =20 - return 0; + return ret; } -#endif =20 static const struct file_operations rfkill_fops =3D { .owner =3D THIS_MODULE, @@ -1343,10 +1365,8 @@ static const struct file_operations rfkill_fops =3D { .write =3D rfkill_fop_write, .poll =3D rfkill_fop_poll, .release =3D rfkill_fop_release, -#ifdef CONFIG_RFKILL_INPUT .unlocked_ioctl =3D rfkill_fop_ioctl, .compat_ioctl =3D compat_ptr_ioctl, -#endif .llseek =3D no_llseek, }; =20 diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 7bd6f8a66a3e..969e532f77a9 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -777,14 +777,12 @@ void rxrpc_propose_ACK(struct rxrpc_call *, u8, u32, = bool, bool, enum rxrpc_propose_ack_trace); void rxrpc_process_call(struct work_struct *); =20 -static inline void rxrpc_reduce_call_timer(struct rxrpc_call *call, - unsigned long expire_at, - unsigned long now, - enum rxrpc_timer_trace why) -{ - trace_rxrpc_timer(call, why, now); - timer_reduce(&call->timer, expire_at); -} +void rxrpc_reduce_call_timer(struct rxrpc_call *call, + unsigned long expire_at, + unsigned long now, + enum rxrpc_timer_trace why); + +void rxrpc_delete_call_timer(struct rxrpc_call *call); =20 /* * call_object.c @@ -808,6 +806,7 @@ void rxrpc_release_calls_on_socket(struct rxrpc_sock *); bool __rxrpc_queue_call(struct rxrpc_call *); bool rxrpc_queue_call(struct rxrpc_call *); void rxrpc_see_call(struct rxrpc_call *); +bool rxrpc_try_get_call(struct rxrpc_call *call, enum rxrpc_call_trace op); void rxrpc_get_call(struct rxrpc_call *, enum rxrpc_call_trace); void rxrpc_put_call(struct rxrpc_call *, enum rxrpc_call_trace); void rxrpc_cleanup_call(struct rxrpc_call *); diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c index df864e692267..22e05de5d1ca 100644 --- a/net/rxrpc/call_event.c +++ b/net/rxrpc/call_event.c @@ -310,7 +310,7 @@ void rxrpc_process_call(struct work_struct *work) } =20 if (call->state =3D=3D RXRPC_CALL_COMPLETE) { - del_timer_sync(&call->timer); + rxrpc_delete_call_timer(call); goto out_put; } =20 diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c index 4eb91d958a48..043508fd8d8a 100644 --- a/net/rxrpc/call_object.c +++ b/net/rxrpc/call_object.c @@ -53,10 +53,30 @@ static void rxrpc_call_timer_expired(struct timer_list = *t) =20 if (call->state < RXRPC_CALL_COMPLETE) { trace_rxrpc_timer(call, rxrpc_timer_expired, jiffies); - rxrpc_queue_call(call); + __rxrpc_queue_call(call); + } else { + rxrpc_put_call(call, rxrpc_call_put); + } +} + +void rxrpc_reduce_call_timer(struct rxrpc_call *call, + unsigned long expire_at, + unsigned long now, + enum rxrpc_timer_trace why) +{ + if (rxrpc_try_get_call(call, rxrpc_call_got_timer)) { + trace_rxrpc_timer(call, why, now); + if (timer_reduce(&call->timer, expire_at)) + rxrpc_put_call(call, rxrpc_call_put_notimer); } } =20 +void rxrpc_delete_call_timer(struct rxrpc_call *call) +{ + if (del_timer_sync(&call->timer)) + rxrpc_put_call(call, rxrpc_call_put_timer); +} + static struct lock_class_key rxrpc_call_user_mutex_lock_class_key; =20 /* @@ -463,6 +483,17 @@ void rxrpc_see_call(struct rxrpc_call *call) } } =20 +bool rxrpc_try_get_call(struct rxrpc_call *call, enum rxrpc_call_trace op) +{ + const void *here =3D __builtin_return_address(0); + int n =3D atomic_fetch_add_unless(&call->usage, 1, 0); + + if (n =3D=3D 0) + return false; + trace_rxrpc_call(call->debug_id, op, n, here, NULL); + return true; +} + /* * Note the addition of a ref on a call. */ @@ -510,8 +541,7 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct r= xrpc_call *call) spin_unlock_bh(&call->lock); =20 rxrpc_put_call_slot(call); - - del_timer_sync(&call->timer); + rxrpc_delete_call_timer(call); =20 /* Make sure we don't get any more notifications */ write_lock_bh(&rx->recvmsg_lock); @@ -618,6 +648,8 @@ static void rxrpc_destroy_call(struct work_struct *work) struct rxrpc_call *call =3D container_of(work, struct rxrpc_call, process= or); struct rxrpc_net *rxnet =3D call->rxnet; =20 + rxrpc_delete_call_timer(call); + rxrpc_put_connection(call->conn); rxrpc_put_peer(call->peer); kfree(call->rxtx_buffer); @@ -652,8 +684,6 @@ void rxrpc_cleanup_call(struct rxrpc_call *call) =20 memset(&call->sock_node, 0xcd, sizeof(call->sock_node)); =20 - del_timer_sync(&call->timer); - ASSERTCMP(call->state, =3D=3D, RXRPC_CALL_COMPLETE); ASSERT(test_bit(RXRPC_CALL_RELEASED, &call->flags)); =20 diff --git a/net/rxrpc/server_key.c b/net/rxrpc/server_key.c index ead3471307ee..ee269e0e6ee8 100644 --- a/net/rxrpc/server_key.c +++ b/net/rxrpc/server_key.c @@ -84,6 +84,9 @@ static int rxrpc_preparse_s(struct key_preparsed_payload = *prep) =20 prep->payload.data[1] =3D (struct rxrpc_security *)sec; =20 + if (!sec->preparse_server_key) + return -EINVAL; + return sec->preparse_server_key(prep); } =20 @@ -91,7 +94,7 @@ static void rxrpc_free_preparse_s(struct key_preparsed_pa= yload *prep) { const struct rxrpc_security *sec =3D prep->payload.data[1]; =20 - if (sec) + if (sec && sec->free_preparse_server_key) sec->free_preparse_server_key(prep); } =20 @@ -99,7 +102,7 @@ static void rxrpc_destroy_s(struct key *key) { const struct rxrpc_security *sec =3D key->payload.data[1]; =20 - if (sec) + if (sec && sec->destroy_server_key) sec->destroy_server_key(key); } =20 diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c index 4ffea1290ce1..553bf41671a6 100644 --- a/net/sched/act_ct.c +++ b/net/sched/act_ct.c @@ -583,22 +583,25 @@ static bool tcf_ct_skb_nfct_cached(struct net *net, s= truct sk_buff *skb, if (!ct) return false; if (!net_eq(net, read_pnet(&ct->ct_net))) - return false; + goto drop_ct; if (nf_ct_zone(ct)->id !=3D zone_id) - return false; + goto drop_ct; =20 /* Force conntrack entry direction. */ if (force && CTINFO2DIR(ctinfo) !=3D IP_CT_DIR_ORIGINAL) { if (nf_ct_is_confirmed(ct)) nf_ct_kill(ct); =20 - nf_conntrack_put(&ct->ct_general); - nf_ct_set(skb, NULL, IP_CT_UNTRACKED); - - return false; + goto drop_ct; } =20 return true; + +drop_ct: + nf_ct_put(ct); + nf_ct_set(skb, NULL, IP_CT_UNTRACKED); + + return false; } =20 /* Trim the skb to the length specified by the IP/IPv6 header, @@ -757,7 +760,7 @@ static void tcf_ct_params_free(struct rcu_head *head) tcf_ct_flow_table_put(params); =20 if (params->tmpl) - nf_conntrack_put(¶ms->tmpl->ct_general); + nf_ct_put(params->tmpl); kfree(params); } =20 @@ -967,7 +970,7 @@ static int tcf_ct_act(struct sk_buff *skb, const struct= tc_action *a, tc_skb_cb(skb)->post_ct =3D false; ct =3D nf_ct_get(skb, &ctinfo); if (ct) { - nf_conntrack_put(&ct->ct_general); + nf_ct_put(ct); nf_ct_set(skb, NULL, IP_CT_UNTRACKED); } =20 diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 354c1c4de19b..5633fbb1ba3c 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -930,6 +930,11 @@ enum sctp_disposition sctp_sf_do_5_1E_ca(struct net *n= et, if (!sctp_vtag_verify(chunk, asoc)) return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); =20 + /* Set peer label for connection. */ + if (security_sctp_assoc_established((struct sctp_association *)asoc, + chunk->skb)) + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); + /* Verify that the chunk length for the COOKIE-ACK is OK. * If we don't do this, any bundled chunks may be junked. */ @@ -945,9 +950,6 @@ enum sctp_disposition sctp_sf_do_5_1E_ca(struct net *ne= t, */ sctp_add_cmd_sf(commands, SCTP_CMD_INIT_COUNTER_RESET, SCTP_NULL()); =20 - /* Set peer label for connection. */ - security_inet_conn_established(ep->base.sk, chunk->skb); - /* RFC 2960 5.1 Normal Establishment of an Association * * E) Upon reception of the COOKIE ACK, endpoint "A" will move diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index c83fe618767c..b36d235d2d6d 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1065,7 +1065,9 @@ rpc_task_get_next_xprt(struct rpc_clnt *clnt) static void rpc_task_set_transport(struct rpc_task *task, struct rpc_clnt *clnt) { - if (task->tk_xprt) + if (task->tk_xprt && + !(test_bit(XPRT_OFFLINE, &task->tk_xprt->state) && + (task->tk_flags & RPC_TASK_MOVEABLE))) return; if (task->tk_flags & RPC_TASK_NO_ROUND_ROBIN) task->tk_xprt =3D rpc_task_get_first_xprt(clnt); @@ -1085,8 +1087,6 @@ void rpc_task_set_client(struct rpc_task *task, struc= t rpc_clnt *clnt) task->tk_flags |=3D RPC_TASK_TIMEOUT; if (clnt->cl_noretranstimeo) task->tk_flags |=3D RPC_TASK_NO_RETRANS_TIMEOUT; - if (atomic_read(&clnt->cl_swapper)) - task->tk_flags |=3D RPC_TASK_SWAPPER; /* Add to the client's list of all tasks */ spin_lock(&clnt->cl_lock); list_add_tail(&task->tk_task, &clnt->cl_tasks); diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index e2c835482791..ae295844ac55 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -876,6 +876,15 @@ void rpc_release_calldata(const struct rpc_call_ops *o= ps, void *calldata) ops->rpc_release(calldata); } =20 +static bool xprt_needs_memalloc(struct rpc_xprt *xprt, struct rpc_task *tk) +{ + if (!xprt) + return false; + if (!atomic_read(&xprt->swapper)) + return false; + return test_bit(XPRT_LOCKED, &xprt->state) && xprt->snd_task =3D=3D tk; +} + /* * This is the RPC `scheduler' (or rather, the finite state machine). */ @@ -884,6 +893,7 @@ static void __rpc_execute(struct rpc_task *task) struct rpc_wait_queue *queue; int task_is_async =3D RPC_IS_ASYNC(task); int status =3D 0; + unsigned long pflags =3D current->flags; =20 WARN_ON_ONCE(RPC_IS_QUEUED(task)); if (RPC_IS_QUEUED(task)) @@ -906,6 +916,10 @@ static void __rpc_execute(struct rpc_task *task) } if (!do_action) break; + if (RPC_IS_SWAPPER(task) || + xprt_needs_memalloc(task->tk_xprt, task)) + current->flags |=3D PF_MEMALLOC; + trace_rpc_task_run_action(task, do_action); do_action(task); =20 @@ -943,7 +957,7 @@ static void __rpc_execute(struct rpc_task *task) rpc_clear_running(task); spin_unlock(&queue->lock); if (task_is_async) - return; + goto out; =20 /* sync task: sleep here */ trace_rpc_task_sync_sleep(task, task->tk_action); @@ -967,6 +981,8 @@ static void __rpc_execute(struct rpc_task *task) =20 /* Release all resources associated with the task */ rpc_release_task(task); +out: + current_restore_flags(pflags, PF_MEMALLOC); } =20 /* @@ -1023,8 +1039,8 @@ int rpc_malloc(struct rpc_task *task) struct rpc_buffer *buf; gfp_t gfp =3D GFP_NOFS; =20 - if (RPC_IS_SWAPPER(task)) - gfp =3D __GFP_MEMALLOC | GFP_NOWAIT | __GFP_NOWARN; + if (RPC_IS_ASYNC(task)) + gfp =3D GFP_NOWAIT | __GFP_NOWARN; =20 size +=3D sizeof(struct rpc_buffer); if (size <=3D RPC_BUFFER_MAXSIZE) diff --git a/net/sunrpc/sysfs.c b/net/sunrpc/sysfs.c index 0c28280dd3bc..5d39bb2b01f1 100644 --- a/net/sunrpc/sysfs.c +++ b/net/sunrpc/sysfs.c @@ -97,7 +97,7 @@ static ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject= *kobj, return 0; ret =3D sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]); xprt_put(xprt); - return ret + 1; + return ret; } =20 static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj, @@ -105,33 +105,31 @@ static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kob= ject *kobj, char *buf) { struct rpc_xprt *xprt =3D rpc_sysfs_xprt_kobj_get_xprt(kobj); - struct sockaddr_storage saddr; - struct sock_xprt *sock; - ssize_t ret =3D -1; + size_t buflen =3D PAGE_SIZE; + ssize_t ret =3D -ENOTSOCK; =20 if (!xprt || !xprt_connected(xprt)) { - xprt_put(xprt); - return -ENOTCONN; + ret =3D -ENOTCONN; + } else if (xprt->ops->get_srcaddr) { + ret =3D xprt->ops->get_srcaddr(xprt, buf, buflen); + if (ret > 0) { + if (ret < buflen - 1) { + buf[ret] =3D '\n'; + ret++; + buf[ret] =3D '\0'; + } + } } - - sock =3D container_of(xprt, struct sock_xprt, xprt); - mutex_lock(&sock->recv_mutex); - if (sock->sock =3D=3D NULL || - kernel_getsockname(sock->sock, (struct sockaddr *)&saddr) < 0) - goto out; - - ret =3D sprintf(buf, "%pISc\n", &saddr); -out: - mutex_unlock(&sock->recv_mutex); xprt_put(xprt); - return ret + 1; + return ret; } =20 static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) + struct kobj_attribute *attr, char *buf) { struct rpc_xprt *xprt =3D rpc_sysfs_xprt_kobj_get_xprt(kobj); + unsigned short srcport =3D 0; + size_t buflen =3D PAGE_SIZE; ssize_t ret; =20 if (!xprt || !xprt_connected(xprt)) { @@ -139,7 +137,11 @@ static ssize_t rpc_sysfs_xprt_info_show(struct kobject= *kobj, return -ENOTCONN; } =20 - ret =3D sprintf(buf, "last_used=3D%lu\ncur_cong=3D%lu\ncong_win=3D%lu\n" + if (xprt->ops->get_srcport) + srcport =3D xprt->ops->get_srcport(xprt); + + ret =3D snprintf(buf, buflen, + "last_used=3D%lu\ncur_cong=3D%lu\ncong_win=3D%lu\n" "max_num_slots=3D%u\nmin_num_slots=3D%u\nnum_reqs=3D%u\n" "binding_q_len=3D%u\nsending_q_len=3D%u\npending_q_len=3D%u\n" "backlog_q_len=3D%u\nmain_xprt=3D%d\nsrc_port=3D%u\n" @@ -147,14 +149,11 @@ static ssize_t rpc_sysfs_xprt_info_show(struct kobjec= t *kobj, xprt->last_used, xprt->cong, xprt->cwnd, xprt->max_reqs, xprt->min_reqs, xprt->num_reqs, xprt->binding.qlen, xprt->sending.qlen, xprt->pending.qlen, - xprt->backlog.qlen, xprt->main, - (xprt->xprt_class->ident =3D=3D XPRT_TRANSPORT_TCP) ? - get_srcport(xprt) : 0, + xprt->backlog.qlen, xprt->main, srcport, atomic_long_read(&xprt->queuelen), - (xprt->xprt_class->ident =3D=3D XPRT_TRANSPORT_TCP) ? - xprt->address_strings[RPC_DISPLAY_PORT] : "0"); + xprt->address_strings[RPC_DISPLAY_PORT]); xprt_put(xprt); - return ret + 1; + return ret; } =20 static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj, @@ -201,7 +200,7 @@ static ssize_t rpc_sysfs_xprt_state_show(struct kobject= *kobj, } =20 xprt_put(xprt); - return ret + 1; + return ret; } =20 static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj, @@ -220,7 +219,7 @@ static ssize_t rpc_sysfs_xprt_switch_info_show(struct k= object *kobj, xprt_switch->xps_nunique_destaddr_xprts, atomic_long_read(&xprt_switch->xps_queuelen)); xprt_switch_put(xprt_switch); - return ret + 1; + return ret; } =20 static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj, diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index a02de2bddb28..396a74974f60 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1503,6 +1503,9 @@ bool xprt_prepare_transmit(struct rpc_task *task) return false; =20 } + if (atomic_read(&xprt->swapper)) + /* This will be clear in __rpc_execute */ + current->flags |=3D PF_MEMALLOC; return true; } =20 @@ -2112,7 +2115,14 @@ static void xprt_destroy(struct rpc_xprt *xprt) */ wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_UNINTERRUPTIBLE); =20 + /* + * xprt_schedule_autodisconnect() can run after XPRT_LOCKED + * is cleared. We use ->transport_lock to ensure the mod_timer() + * can only run *before* del_time_sync(), never after. + */ + spin_lock(&xprt->transport_lock); del_timer_sync(&xprt->timer); + spin_unlock(&xprt->transport_lock); =20 /* * Destroy sockets etc from the system workqueue so they can diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transpor= t.c index 16e5696314a4..6268af7e0310 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -239,8 +239,11 @@ xprt_rdma_connect_worker(struct work_struct *work) struct rpcrdma_xprt *r_xprt =3D container_of(work, struct rpcrdma_xprt, rx_connect_worker.work); struct rpc_xprt *xprt =3D &r_xprt->rx_xprt; + unsigned int pflags =3D current->flags; int rc; =20 + if (atomic_read(&xprt->swapper)) + current->flags |=3D PF_MEMALLOC; rc =3D rpcrdma_xprt_connect(r_xprt); xprt_clear_connecting(xprt); if (!rc) { @@ -254,6 +257,7 @@ xprt_rdma_connect_worker(struct work_struct *work) rpcrdma_xprt_disconnect(r_xprt); xprt_unlock_connect(xprt, r_xprt); xprt_wake_pending_tasks(xprt, rc); + current_restore_flags(pflags, PF_MEMALLOC); } =20 /** @@ -574,8 +578,8 @@ xprt_rdma_allocate(struct rpc_task *task) gfp_t flags; =20 flags =3D RPCRDMA_DEF_GFP; - if (RPC_IS_SWAPPER(task)) - flags =3D __GFP_MEMALLOC | GFP_NOWAIT | __GFP_NOWARN; + if (RPC_IS_ASYNC(task)) + flags =3D GFP_NOWAIT | __GFP_NOWARN; =20 if (!rpcrdma_check_regbuf(r_xprt, req->rl_sendbuf, rqst->rq_callsize, flags)) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 03770e56df36..37d961c1a5c9 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1638,7 +1638,7 @@ static int xs_get_srcport(struct sock_xprt *transport) return port; } =20 -unsigned short get_srcport(struct rpc_xprt *xprt) +static unsigned short xs_sock_srcport(struct rpc_xprt *xprt) { struct sock_xprt *sock =3D container_of(xprt, struct sock_xprt, xprt); unsigned short ret =3D 0; @@ -1648,7 +1648,25 @@ unsigned short get_srcport(struct rpc_xprt *xprt) mutex_unlock(&sock->recv_mutex); return ret; } -EXPORT_SYMBOL(get_srcport); + +static int xs_sock_srcaddr(struct rpc_xprt *xprt, char *buf, size_t buflen) +{ + struct sock_xprt *sock =3D container_of(xprt, struct sock_xprt, xprt); + union { + struct sockaddr sa; + struct sockaddr_storage st; + } saddr; + int ret =3D -ENOTCONN; + + mutex_lock(&sock->recv_mutex); + if (sock->sock) { + ret =3D kernel_getsockname(sock->sock, &saddr.sa); + if (ret >=3D 0) + ret =3D snprintf(buf, buflen, "%pISc", &saddr.sa); + } + mutex_unlock(&sock->recv_mutex); + return ret; +} =20 static unsigned short xs_next_srcport(struct sock_xprt *transport, unsigne= d short port) { @@ -2052,7 +2070,10 @@ static void xs_udp_setup_socket(struct work_struct *= work) struct rpc_xprt *xprt =3D &transport->xprt; struct socket *sock; int status =3D -EIO; + unsigned int pflags =3D current->flags; =20 + if (atomic_read(&xprt->swapper)) + current->flags |=3D PF_MEMALLOC; sock =3D xs_create_sock(xprt, transport, xs_addr(xprt)->sa_family, SOCK_DGRAM, IPPROTO_UDP, false); @@ -2072,6 +2093,7 @@ static void xs_udp_setup_socket(struct work_struct *w= ork) xprt_clear_connecting(xprt); xprt_unlock_connect(xprt, transport); xprt_wake_pending_tasks(xprt, status); + current_restore_flags(pflags, PF_MEMALLOC); } =20 /** @@ -2231,11 +2253,19 @@ static void xs_tcp_setup_socket(struct work_struct = *work) struct socket *sock =3D transport->sock; struct rpc_xprt *xprt =3D &transport->xprt; int status; + unsigned int pflags =3D current->flags; + + if (atomic_read(&xprt->swapper)) + current->flags |=3D PF_MEMALLOC; =20 - if (!sock) { - sock =3D xs_create_sock(xprt, transport, - xs_addr(xprt)->sa_family, SOCK_STREAM, - IPPROTO_TCP, true); + if (xprt_connected(xprt)) + goto out; + if (test_and_clear_bit(XPRT_SOCK_CONNECT_SENT, + &transport->sock_state) || + !sock) { + xs_reset_transport(transport); + sock =3D xs_create_sock(xprt, transport, xs_addr(xprt)->sa_family, + SOCK_STREAM, IPPROTO_TCP, true); if (IS_ERR(sock)) { xprt_wake_pending_tasks(xprt, PTR_ERR(sock)); goto out; @@ -2259,6 +2289,7 @@ static void xs_tcp_setup_socket(struct work_struct *w= ork) fallthrough; case -EINPROGRESS: /* SYN_SENT! */ + set_bit(XPRT_SOCK_CONNECT_SENT, &transport->sock_state); if (xprt->reestablish_timeout < XS_TCP_INIT_REEST_TO) xprt->reestablish_timeout =3D XS_TCP_INIT_REEST_TO; fallthrough; @@ -2296,6 +2327,7 @@ static void xs_tcp_setup_socket(struct work_struct *w= ork) xprt_clear_connecting(xprt); out_unlock: xprt_unlock_connect(xprt, transport); + current_restore_flags(pflags, PF_MEMALLOC); } =20 /** @@ -2319,13 +2351,9 @@ static void xs_connect(struct rpc_xprt *xprt, struct= rpc_task *task) =20 WARN_ON_ONCE(!xprt_lock_connect(xprt, task, transport)); =20 - if (transport->sock !=3D NULL && !xprt_connecting(xprt)) { + if (transport->sock !=3D NULL) { dprintk("RPC: xs_connect delayed xprt %p for %lu " - "seconds\n", - xprt, xprt->reestablish_timeout / HZ); - - /* Start by resetting any existing state */ - xs_reset_transport(transport); + "seconds\n", xprt, xprt->reestablish_timeout / HZ); =20 delay =3D xprt_reconnect_delay(xprt); xprt_reconnect_backoff(xprt, XS_TCP_INIT_REEST_TO); @@ -2621,6 +2649,8 @@ static const struct rpc_xprt_ops xs_udp_ops =3D { .rpcbind =3D rpcb_getport_async, .set_port =3D xs_set_port, .connect =3D xs_connect, + .get_srcaddr =3D xs_sock_srcaddr, + .get_srcport =3D xs_sock_srcport, .buf_alloc =3D rpc_malloc, .buf_free =3D rpc_free, .send_request =3D xs_udp_send_request, @@ -2643,6 +2673,8 @@ static const struct rpc_xprt_ops xs_tcp_ops =3D { .rpcbind =3D rpcb_getport_async, .set_port =3D xs_set_port, .connect =3D xs_connect, + .get_srcaddr =3D xs_sock_srcaddr, + .get_srcport =3D xs_sock_srcport, .buf_alloc =3D rpc_malloc, .buf_free =3D rpc_free, .prepare_request =3D xs_stream_prepare_request, diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 7545321c3440..17f8c523e33b 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -2852,7 +2852,8 @@ static void tipc_sk_retry_connect(struct sock *sk, st= ruct sk_buff_head *list) =20 /* Try again later if dest link is congested */ if (tsk->cong_link_cnt) { - sk_reset_timer(sk, &sk->sk_timer, msecs_to_jiffies(100)); + sk_reset_timer(sk, &sk->sk_timer, + jiffies + msecs_to_jiffies(100)); return; } /* Prepare SYN for retransmit */ diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index b0bfc78e421c..62f47821d783 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1996,7 +1996,7 @@ static int queue_oob(struct socket *sock, struct msgh= dr *msg, struct sock *other if (ousk->oob_skb) consume_skb(ousk->oob_skb); =20 - ousk->oob_skb =3D skb; + WRITE_ONCE(ousk->oob_skb, skb); =20 scm_stat_add(other, skb); skb_queue_tail(&other->sk_receive_queue, skb); @@ -2514,9 +2514,8 @@ static int unix_stream_recv_urg(struct unix_stream_re= ad_state *state) =20 oob_skb =3D u->oob_skb; =20 - if (!(state->flags & MSG_PEEK)) { - u->oob_skb =3D NULL; - } + if (!(state->flags & MSG_PEEK)) + WRITE_ONCE(u->oob_skb, NULL); =20 unix_state_unlock(sk); =20 @@ -2551,7 +2550,7 @@ static struct sk_buff *manage_oob(struct sk_buff *skb= , struct sock *sk, skb =3D NULL; } else if (sock_flag(sk, SOCK_URGINLINE)) { if (!(flags & MSG_PEEK)) { - u->oob_skb =3D NULL; + WRITE_ONCE(u->oob_skb, NULL); consume_skb(skb); } } else if (!(flags & MSG_PEEK)) { @@ -3006,11 +3005,10 @@ static int unix_ioctl(struct socket *sock, unsigned= int cmd, unsigned long arg) case SIOCATMARK: { struct sk_buff *skb; - struct unix_sock *u =3D unix_sk(sk); int answ =3D 0; =20 skb =3D skb_peek(&sk->sk_receive_queue); - if (skb && skb =3D=3D u->oob_skb) + if (skb && skb =3D=3D READ_ONCE(unix_sk(sk)->oob_skb)) answ =3D 1; err =3D put_user(answ, (int __user *)arg); } @@ -3051,6 +3049,10 @@ static __poll_t unix_poll(struct file *file, struct = socket *sock, poll_table *wa mask |=3D EPOLLIN | EPOLLRDNORM; if (sk_is_readable(sk)) mask |=3D EPOLLIN | EPOLLRDNORM; +#if IS_ENABLED(CONFIG_AF_UNIX_OOB) + if (READ_ONCE(unix_sk(sk)->oob_skb)) + mask |=3D EPOLLPRI; +#endif =20 /* Connection-based need to check for termination and startup */ if ((sk->sk_type =3D=3D SOCK_STREAM || sk->sk_type =3D=3D SOCK_SEQPACKET)= && diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transp= ort.c index dad9ca65f4f9..c5f936fbf876 100644 --- a/net/vmw_vsock/virtio_transport.c +++ b/net/vmw_vsock/virtio_transport.c @@ -622,6 +622,13 @@ static int virtio_vsock_probe(struct virtio_device *vd= ev) INIT_WORK(&vsock->event_work, virtio_transport_event_work); INIT_WORK(&vsock->send_pkt_work, virtio_transport_send_pkt_work); =20 + if (virtio_has_feature(vdev, VIRTIO_VSOCK_F_SEQPACKET)) + vsock->seqpacket_allow =3D true; + + vdev->priv =3D vsock; + + virtio_device_ready(vdev); + mutex_lock(&vsock->tx_lock); vsock->tx_run =3D true; mutex_unlock(&vsock->tx_lock); @@ -636,10 +643,6 @@ static int virtio_vsock_probe(struct virtio_device *vd= ev) vsock->event_run =3D true; mutex_unlock(&vsock->event_lock); =20 - if (virtio_has_feature(vdev, VIRTIO_VSOCK_F_SEQPACKET)) - vsock->seqpacket_allow =3D true; - - vdev->priv =3D vsock; rcu_assign_pointer(the_virtio_vsock, vsock); =20 mutex_unlock(&the_virtio_vsock_mutex); diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 3583354a7d7f..3a171828638b 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -1765,10 +1765,15 @@ void x25_kill_by_neigh(struct x25_neigh *nb) =20 write_lock_bh(&x25_list_lock); =20 - sk_for_each(s, &x25_list) - if (x25_sk(s)->neighbour =3D=3D nb) + sk_for_each(s, &x25_list) { + if (x25_sk(s)->neighbour =3D=3D nb) { + write_unlock_bh(&x25_list_lock); + lock_sock(s); x25_disconnect(s, ENETUNREACH, 0, 0); - + release_sock(s); + write_lock_bh(&x25_list_lock); + } + } write_unlock_bh(&x25_list_lock); =20 /* Remove any related forwards */ diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c index f16074eb53c7..468e9b7e3edf 100644 --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c @@ -403,18 +403,8 @@ EXPORT_SYMBOL(xsk_tx_peek_release_desc_batch); static int xsk_wakeup(struct xdp_sock *xs, u8 flags) { struct net_device *dev =3D xs->dev; - int err; - - rcu_read_lock(); - err =3D dev->netdev_ops->ndo_xsk_wakeup(dev, xs->queue_id, flags); - rcu_read_unlock(); - - return err; -} =20 -static int xsk_zc_xmit(struct xdp_sock *xs) -{ - return xsk_wakeup(xs, XDP_WAKEUP_TX); + return dev->netdev_ops->ndo_xsk_wakeup(dev, xs->queue_id, flags); } =20 static void xsk_destruct_skb(struct sk_buff *skb) @@ -533,6 +523,12 @@ static int xsk_generic_xmit(struct sock *sk) =20 mutex_lock(&xs->mutex); =20 + /* Since we dropped the RCU read lock, the socket state might have change= d. */ + if (unlikely(!xsk_is_bound(xs))) { + err =3D -ENXIO; + goto out; + } + if (xs->queue_id >=3D xs->dev->real_num_tx_queues) goto out; =20 @@ -596,16 +592,26 @@ static int xsk_generic_xmit(struct sock *sk) return err; } =20 -static int __xsk_sendmsg(struct sock *sk) +static int xsk_xmit(struct sock *sk) { struct xdp_sock *xs =3D xdp_sk(sk); + int ret; =20 if (unlikely(!(xs->dev->flags & IFF_UP))) return -ENETDOWN; if (unlikely(!xs->tx)) return -ENOBUFS; =20 - return xs->zc ? xsk_zc_xmit(xs) : xsk_generic_xmit(sk); + if (xs->zc) + return xsk_wakeup(xs, XDP_WAKEUP_TX); + + /* Drop the RCU lock since the SKB path might sleep. */ + rcu_read_unlock(); + ret =3D xsk_generic_xmit(sk); + /* Reaquire RCU lock before going into common code. */ + rcu_read_lock(); + + return ret; } =20 static bool xsk_no_wakeup(struct sock *sk) @@ -619,7 +625,7 @@ static bool xsk_no_wakeup(struct sock *sk) #endif } =20 -static int xsk_sendmsg(struct socket *sock, struct msghdr *m, size_t total= _len) +static int __xsk_sendmsg(struct socket *sock, struct msghdr *m, size_t tot= al_len) { bool need_wait =3D !(m->msg_flags & MSG_DONTWAIT); struct sock *sk =3D sock->sk; @@ -639,11 +645,22 @@ static int xsk_sendmsg(struct socket *sock, struct ms= ghdr *m, size_t total_len) =20 pool =3D xs->pool; if (pool->cached_need_wakeup & XDP_WAKEUP_TX) - return __xsk_sendmsg(sk); + return xsk_xmit(sk); return 0; } =20 -static int xsk_recvmsg(struct socket *sock, struct msghdr *m, size_t len, = int flags) +static int xsk_sendmsg(struct socket *sock, struct msghdr *m, size_t total= _len) +{ + int ret; + + rcu_read_lock(); + ret =3D __xsk_sendmsg(sock, m, total_len); + rcu_read_unlock(); + + return ret; +} + +static int __xsk_recvmsg(struct socket *sock, struct msghdr *m, size_t len= , int flags) { bool need_wait =3D !(flags & MSG_DONTWAIT); struct sock *sk =3D sock->sk; @@ -669,6 +686,17 @@ static int xsk_recvmsg(struct socket *sock, struct msg= hdr *m, size_t len, int fl return 0; } =20 +static int xsk_recvmsg(struct socket *sock, struct msghdr *m, size_t len, = int flags) +{ + int ret; + + rcu_read_lock(); + ret =3D __xsk_recvmsg(sock, m, len, flags); + rcu_read_unlock(); + + return ret; +} + static __poll_t xsk_poll(struct file *file, struct socket *sock, struct poll_table_struct *wait) { @@ -679,8 +707,11 @@ static __poll_t xsk_poll(struct file *file, struct soc= ket *sock, =20 sock_poll_wait(file, sock, wait); =20 - if (unlikely(!xsk_is_bound(xs))) + rcu_read_lock(); + if (unlikely(!xsk_is_bound(xs))) { + rcu_read_unlock(); return mask; + } =20 pool =3D xs->pool; =20 @@ -689,7 +720,7 @@ static __poll_t xsk_poll(struct file *file, struct sock= et *sock, xsk_wakeup(xs, pool->cached_need_wakeup); else /* Poll needs to drive Tx also in copy mode */ - __xsk_sendmsg(sk); + xsk_xmit(sk); } =20 if (xs->rx && !xskq_prod_is_empty(xs->rx)) @@ -697,6 +728,7 @@ static __poll_t xsk_poll(struct file *file, struct sock= et *sock, if (xs->tx && xsk_tx_writeable(xs)) mask |=3D EPOLLOUT | EPOLLWRNORM; =20 + rcu_read_unlock(); return mask; } =20 @@ -728,7 +760,6 @@ static void xsk_unbind_dev(struct xdp_sock *xs) =20 /* Wait for driver to stop using the xdp socket. */ xp_del_xsk(xs->pool, xs); - xs->dev =3D NULL; synchronize_net(); dev_put(dev); } diff --git a/net/xdp/xsk_buff_pool.c b/net/xdp/xsk_buff_pool.c index fd39bb660ebc..0202a90b65e3 100644 --- a/net/xdp/xsk_buff_pool.c +++ b/net/xdp/xsk_buff_pool.c @@ -584,9 +584,13 @@ u32 xp_alloc_batch(struct xsk_buff_pool *pool, struct = xdp_buff **xdp, u32 max) u32 nb_entries1 =3D 0, nb_entries2; =20 if (unlikely(pool->dma_need_sync)) { + struct xdp_buff *buff; + /* Slow path */ - *xdp =3D xp_alloc(pool); - return !!*xdp; + buff =3D xp_alloc(pool); + if (buff) + *xdp =3D buff; + return !!buff; } =20 if (unlikely(pool->free_list_cnt)) { diff --git a/net/xfrm/xfrm_interface.c b/net/xfrm/xfrm_interface.c index 4e3c62d1ad9e..1e8b26eecb3f 100644 --- a/net/xfrm/xfrm_interface.c +++ b/net/xfrm/xfrm_interface.c @@ -304,7 +304,10 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *de= v, struct flowi *fl) if (mtu < IPV6_MIN_MTU) mtu =3D IPV6_MIN_MTU; =20 - icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); + if (skb->len > 1280) + icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); + else + goto xmit; } else { if (!(ip_hdr(skb)->frag_off & htons(IP_DF))) goto xmit; diff --git a/samples/bpf/xdpsock_user.c b/samples/bpf/xdpsock_user.c index 49d7a6ad7e39..1fb79b3ecdd5 100644 --- a/samples/bpf/xdpsock_user.c +++ b/samples/bpf/xdpsock_user.c @@ -1673,14 +1673,15 @@ int main(int argc, char **argv) =20 setlocale(LC_ALL, ""); =20 + prev_time =3D get_nsecs(); + start_time =3D prev_time; + if (!opt_quiet) { ret =3D pthread_create(&pt, NULL, poller, NULL); if (ret) exit_with_error(ret); } =20 - prev_time =3D get_nsecs(); - start_time =3D prev_time; =20 if (opt_bench =3D=3D BENCH_RXDROP) rx_drop_all(); diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c index 7a15910d2171..8859fc193542 100644 --- a/samples/landlock/sandboxer.c +++ b/samples/landlock/sandboxer.c @@ -134,6 +134,7 @@ static int populate_ruleset( ret =3D 0; =20 out_free_name: + free(path_list); free(env_path_name); return ret; } diff --git a/scripts/atomic/fallbacks/read_acquire b/scripts/atomic/fallbac= ks/read_acquire index 803ba7561076..a0ea1d26e6b2 100755 --- a/scripts/atomic/fallbacks/read_acquire +++ b/scripts/atomic/fallbacks/read_acquire @@ -2,6 +2,15 @@ cat <counter); + ${int} ret; + + if (__native_word(${atomic}_t)) { + ret =3D smp_load_acquire(&(v)->counter); + } else { + ret =3D arch_${atomic}_read(v); + __atomic_acquire_fence(); + } + + return ret; } EOF diff --git a/scripts/atomic/fallbacks/set_release b/scripts/atomic/fallback= s/set_release index 86ede759f24e..05cdb7f42477 100755 --- a/scripts/atomic/fallbacks/set_release +++ b/scripts/atomic/fallbacks/set_release @@ -2,6 +2,11 @@ cat <counter, i); + if (__native_word(${atomic}_t)) { + smp_store_release(&(v)->counter, i); + } else { + __atomic_release_fence(); + arch_${atomic}_set(v, i); + } } EOF diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile index 95aaf7431bff..1cba78e1dce6 100644 --- a/scripts/dtc/Makefile +++ b/scripts/dtc/Makefile @@ -29,7 +29,7 @@ dtc-objs +=3D yamltree.o # To include installed in a non-default path HOSTCFLAGS_yamltree.o :=3D $(shell pkg-config --cflags yaml-0.1) # To link libyaml installed in a non-default path -HOSTLDLIBS_dtc :=3D $(shell pkg-config yaml-0.1 --libs) +HOSTLDLIBS_dtc :=3D $(shell pkg-config --libs yaml-0.1) endif =20 # Generated files need one more search path to include headers in source t= ree diff --git a/scripts/gcc-plugins/stackleak_plugin.c b/scripts/gcc-plugins/s= tackleak_plugin.c index e9db7dcb3e5f..b04aa8e91a41 100644 --- a/scripts/gcc-plugins/stackleak_plugin.c +++ b/scripts/gcc-plugins/stackleak_plugin.c @@ -429,6 +429,23 @@ static unsigned int stackleak_cleanup_execute(void) return 0; } =20 +/* + * STRING_CST may or may not be NUL terminated: + * https://gcc.gnu.org/onlinedocs/gccint/Constant-expressions.html + */ +static inline bool string_equal(tree node, const char *string, int length) +{ + if (TREE_STRING_LENGTH(node) < length) + return false; + if (TREE_STRING_LENGTH(node) > length + 1) + return false; + if (TREE_STRING_LENGTH(node) =3D=3D length + 1 && + TREE_STRING_POINTER(node)[length] !=3D '\0') + return false; + return !memcmp(TREE_STRING_POINTER(node), string, length); +} +#define STRING_EQUAL(node, str) string_equal(node, str, strlen(str)) + static bool stackleak_gate(void) { tree section; @@ -438,13 +455,13 @@ static bool stackleak_gate(void) if (section && TREE_VALUE(section)) { section =3D TREE_VALUE(TREE_VALUE(section)); =20 - if (!strncmp(TREE_STRING_POINTER(section), ".init.text", 10)) + if (STRING_EQUAL(section, ".init.text")) return false; - if (!strncmp(TREE_STRING_POINTER(section), ".devinit.text", 13)) + if (STRING_EQUAL(section, ".devinit.text")) return false; - if (!strncmp(TREE_STRING_POINTER(section), ".cpuinit.text", 13)) + if (STRING_EQUAL(section, ".cpuinit.text")) return false; - if (!strncmp(TREE_STRING_POINTER(section), ".meminit.text", 13)) + if (STRING_EQUAL(section, ".meminit.text")) return false; } =20 diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index cb8ab7d91d30..ca491aa2b376 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -669,7 +669,7 @@ static void handle_modversion(const struct module *mod, unsigned int crc; =20 if (sym->st_shndx =3D=3D SHN_UNDEF) { - warn("EXPORT symbol \"%s\" [%s%s] version ...\n" + warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will= not be versioned.\n" "Is \"%s\" prototyped in ?\n", symname, mod->name, mod->is_vmlinux ? "" : ".ko", symname); diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm= _main.c index 08f907382c61..7d87772f0ce6 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -86,7 +86,7 @@ static int __init evm_set_fixmode(char *str) else pr_err("invalid \"%s\" mode", str); =20 - return 0; + return 1; } __setup("evm=3D", evm_set_fixmode); =20 diff --git a/security/keys/keyctl_pkey.c b/security/keys/keyctl_pkey.c index 5de0d599a274..97bc27bbf079 100644 --- a/security/keys/keyctl_pkey.c +++ b/security/keys/keyctl_pkey.c @@ -135,15 +135,23 @@ static int keyctl_pkey_params_get_2(const struct keyc= tl_pkey_params __user *_par =20 switch (op) { case KEYCTL_PKEY_ENCRYPT: + if (uparams.in_len > info.max_dec_size || + uparams.out_len > info.max_enc_size) + return -EINVAL; + break; case KEYCTL_PKEY_DECRYPT: if (uparams.in_len > info.max_enc_size || uparams.out_len > info.max_dec_size) return -EINVAL; break; case KEYCTL_PKEY_SIGN: + if (uparams.in_len > info.max_data_size || + uparams.out_len > info.max_sig_size) + return -EINVAL; + break; case KEYCTL_PKEY_VERIFY: - if (uparams.in_len > info.max_sig_size || - uparams.out_len > info.max_data_size) + if (uparams.in_len > info.max_data_size || + uparams.in2_len > info.max_sig_size) return -EINVAL; break; default: @@ -151,7 +159,7 @@ static int keyctl_pkey_params_get_2(const struct keyctl= _pkey_params __user *_par } =20 params->in_len =3D uparams.in_len; - params->out_len =3D uparams.out_len; + params->out_len =3D uparams.out_len; /* Note: same as in2_len */ return 0; } =20 diff --git a/security/keys/trusted-keys/trusted_core.c b/security/keys/trus= ted-keys/trusted_core.c index d5c891d8d353..9b9d3ef79cbe 100644 --- a/security/keys/trusted-keys/trusted_core.c +++ b/security/keys/trusted-keys/trusted_core.c @@ -27,10 +27,10 @@ module_param_named(source, trusted_key_source, charp, 0= ); MODULE_PARM_DESC(source, "Select trusted keys source (tpm or tee)"); =20 static const struct trusted_key_source trusted_key_sources[] =3D { -#if defined(CONFIG_TCG_TPM) +#if IS_REACHABLE(CONFIG_TCG_TPM) { "tpm", &trusted_key_tpm_ops }, #endif -#if defined(CONFIG_TEE) +#if IS_REACHABLE(CONFIG_TEE) { "tee", &trusted_key_tee_ops }, #endif }; @@ -351,7 +351,7 @@ static int __init init_trusted(void) =20 static void __exit cleanup_trusted(void) { - static_call(trusted_key_exit)(); + static_call_cond(trusted_key_exit)(); } =20 late_initcall(init_trusted); diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c index 32396962f04d..7e27ce394020 100644 --- a/security/landlock/syscalls.c +++ b/security/landlock/syscalls.c @@ -192,7 +192,7 @@ SYSCALL_DEFINE3(landlock_create_ruleset, return PTR_ERR(ruleset); =20 /* Creates anonymous FD referring to the ruleset. */ - ruleset_fd =3D anon_inode_getfd("landlock-ruleset", &ruleset_fops, + ruleset_fd =3D anon_inode_getfd("[landlock-ruleset]", &ruleset_fops, ruleset, O_RDWR | O_CLOEXEC); if (ruleset_fd < 0) landlock_put_ruleset(ruleset); diff --git a/security/security.c b/security/security.c index 64abdfb20bc2..745a8bf66d91 100644 --- a/security/security.c +++ b/security/security.c @@ -884,9 +884,22 @@ int security_fs_context_dup(struct fs_context *fc, str= uct fs_context *src_fc) return call_int_hook(fs_context_dup, 0, fc, src_fc); } =20 -int security_fs_context_parse_param(struct fs_context *fc, struct fs_param= eter *param) +int security_fs_context_parse_param(struct fs_context *fc, + struct fs_parameter *param) { - return call_int_hook(fs_context_parse_param, -ENOPARAM, fc, param); + struct security_hook_list *hp; + int trc; + int rc =3D -ENOPARAM; + + hlist_for_each_entry(hp, &security_hook_heads.fs_context_parse_param, + list) { + trc =3D hp->hook.fs_context_parse_param(fc, param); + if (trc =3D=3D 0) + rc =3D 0; + else if (trc !=3D -ENOPARAM) + return trc; + } + return rc; } =20 int security_sb_alloc(struct super_block *sb) @@ -2399,6 +2412,13 @@ void security_sctp_sk_clone(struct sctp_association = *asoc, struct sock *sk, } EXPORT_SYMBOL(security_sctp_sk_clone); =20 +int security_sctp_assoc_established(struct sctp_association *asoc, + struct sk_buff *skb) +{ + return call_int_hook(sctp_assoc_established, 0, asoc, skb); +} +EXPORT_SYMBOL(security_sctp_assoc_established); + #endif /* CONFIG_SECURITY_NETWORK */ =20 #ifdef CONFIG_SECURITY_INFINIBAND diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 49b4f59db35e..94ef617de9d0 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -355,6 +355,10 @@ static void inode_free_security(struct inode *inode) =20 struct selinux_mnt_opts { const char *fscontext, *context, *rootcontext, *defcontext; + u32 fscontext_sid; + u32 context_sid; + u32 rootcontext_sid; + u32 defcontext_sid; }; =20 static void selinux_free_mnt_opts(void *mnt_opts) @@ -492,7 +496,7 @@ static int selinux_is_sblabel_mnt(struct super_block *s= b) =20 static int sb_check_xattr_support(struct super_block *sb) { - struct superblock_security_struct *sbsec =3D sb->s_security; + struct superblock_security_struct *sbsec =3D selinux_superblock(sb); struct dentry *root =3D sb->s_root; struct inode *root_inode =3D d_backing_inode(root); u32 sid; @@ -611,15 +615,14 @@ static int bad_option(struct superblock_security_stru= ct *sbsec, char flag, return 0; } =20 -static int parse_sid(struct super_block *sb, const char *s, u32 *sid, - gfp_t gfp) +static int parse_sid(struct super_block *sb, const char *s, u32 *sid) { int rc =3D security_context_str_to_sid(&selinux_state, s, - sid, gfp); + sid, GFP_KERNEL); if (rc) pr_warn("SELinux: security_context_str_to_sid" "(%s) failed for (dev %s, type %s) errno=3D%d\n", - s, sb->s_id, sb->s_type->name, rc); + s, sb ? sb->s_id : "?", sb ? sb->s_type->name : "?", rc); return rc; } =20 @@ -686,8 +689,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, */ if (opts) { if (opts->fscontext) { - rc =3D parse_sid(sb, opts->fscontext, &fscontext_sid, - GFP_KERNEL); + rc =3D parse_sid(sb, opts->fscontext, &fscontext_sid); if (rc) goto out; if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, @@ -696,8 +698,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, sbsec->flags |=3D FSCONTEXT_MNT; } if (opts->context) { - rc =3D parse_sid(sb, opts->context, &context_sid, - GFP_KERNEL); + rc =3D parse_sid(sb, opts->context, &context_sid); if (rc) goto out; if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, @@ -706,8 +707,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, sbsec->flags |=3D CONTEXT_MNT; } if (opts->rootcontext) { - rc =3D parse_sid(sb, opts->rootcontext, &rootcontext_sid, - GFP_KERNEL); + rc =3D parse_sid(sb, opts->rootcontext, &rootcontext_sid); if (rc) goto out; if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, @@ -716,8 +716,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, sbsec->flags |=3D ROOTCONTEXT_MNT; } if (opts->defcontext) { - rc =3D parse_sid(sb, opts->defcontext, &defcontext_sid, - GFP_KERNEL); + rc =3D parse_sid(sb, opts->defcontext, &defcontext_sid); if (rc) goto out; if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, @@ -1009,21 +1008,29 @@ static int selinux_add_opt(int token, const char *s= , void **mnt_opts) if (opts->context || opts->defcontext) goto Einval; opts->context =3D s; + if (selinux_initialized(&selinux_state)) + parse_sid(NULL, s, &opts->context_sid); break; case Opt_fscontext: if (opts->fscontext) goto Einval; opts->fscontext =3D s; + if (selinux_initialized(&selinux_state)) + parse_sid(NULL, s, &opts->fscontext_sid); break; case Opt_rootcontext: if (opts->rootcontext) goto Einval; opts->rootcontext =3D s; + if (selinux_initialized(&selinux_state)) + parse_sid(NULL, s, &opts->rootcontext_sid); break; case Opt_defcontext: if (opts->context || opts->defcontext) goto Einval; opts->defcontext =3D s; + if (selinux_initialized(&selinux_state)) + parse_sid(NULL, s, &opts->defcontext_sid); break; } return 0; @@ -2696,9 +2703,7 @@ static int selinux_sb_eat_lsm_opts(char *options, voi= d **mnt_opts) static int selinux_sb_mnt_opts_compat(struct super_block *sb, void *mnt_op= ts) { struct selinux_mnt_opts *opts =3D mnt_opts; - struct superblock_security_struct *sbsec =3D sb->s_security; - u32 sid; - int rc; + struct superblock_security_struct *sbsec =3D selinux_superblock(sb); =20 /* * Superblock not initialized (i.e. no options) - reject if any @@ -2715,34 +2720,36 @@ static int selinux_sb_mnt_opts_compat(struct super_= block *sb, void *mnt_opts) return (sbsec->flags & SE_MNTMASK) ? 1 : 0; =20 if (opts->fscontext) { - rc =3D parse_sid(sb, opts->fscontext, &sid, GFP_NOWAIT); - if (rc) + if (opts->fscontext_sid =3D=3D SECSID_NULL) return 1; - if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid)) + else if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, + opts->fscontext_sid)) return 1; } if (opts->context) { - rc =3D parse_sid(sb, opts->context, &sid, GFP_NOWAIT); - if (rc) + if (opts->context_sid =3D=3D SECSID_NULL) return 1; - if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid)) + else if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, + opts->context_sid)) return 1; } if (opts->rootcontext) { - struct inode_security_struct *root_isec; - - root_isec =3D backing_inode_security(sb->s_root); - rc =3D parse_sid(sb, opts->rootcontext, &sid, GFP_NOWAIT); - if (rc) - return 1; - if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid)) + if (opts->rootcontext_sid =3D=3D SECSID_NULL) return 1; + else { + struct inode_security_struct *root_isec; + + root_isec =3D backing_inode_security(sb->s_root); + if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, + opts->rootcontext_sid)) + return 1; + } } if (opts->defcontext) { - rc =3D parse_sid(sb, opts->defcontext, &sid, GFP_NOWAIT); - if (rc) + if (opts->defcontext_sid =3D=3D SECSID_NULL) return 1; - if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid)) + else if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, + opts->defcontext_sid)) return 1; } return 0; @@ -2762,14 +2769,14 @@ static int selinux_sb_remount(struct super_block *s= b, void *mnt_opts) return 0; =20 if (opts->fscontext) { - rc =3D parse_sid(sb, opts->fscontext, &sid, GFP_KERNEL); + rc =3D parse_sid(sb, opts->fscontext, &sid); if (rc) return rc; if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid)) goto out_bad_option; } if (opts->context) { - rc =3D parse_sid(sb, opts->context, &sid, GFP_KERNEL); + rc =3D parse_sid(sb, opts->context, &sid); if (rc) return rc; if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid)) @@ -2778,14 +2785,14 @@ static int selinux_sb_remount(struct super_block *s= b, void *mnt_opts) if (opts->rootcontext) { struct inode_security_struct *root_isec; root_isec =3D backing_inode_security(sb->s_root); - rc =3D parse_sid(sb, opts->rootcontext, &sid, GFP_KERNEL); + rc =3D parse_sid(sb, opts->rootcontext, &sid); if (rc) return rc; if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid)) goto out_bad_option; } if (opts->defcontext) { - rc =3D parse_sid(sb, opts->defcontext, &sid, GFP_KERNEL); + rc =3D parse_sid(sb, opts->defcontext, &sid); if (rc) return rc; if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid)) @@ -2909,10 +2916,9 @@ static int selinux_fs_context_parse_param(struct fs_= context *fc, return opt; =20 rc =3D selinux_add_opt(opt, param->string, &fc->security); - if (!rc) { + if (!rc) param->string =3D NULL; - rc =3D 1; - } + return rc; } =20 @@ -3794,6 +3800,12 @@ static int selinux_file_ioctl(struct file *file, uns= igned int cmd, CAP_OPT_NONE, true); break; =20 + case FIOCLEX: + case FIONCLEX: + if (!selinux_policycap_ioctl_skip_cloexec()) + error =3D ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd); + break; + /* default case assumes that the command will go * to the file's ioctl() function. */ @@ -5348,37 +5360,38 @@ static void selinux_sock_graft(struct sock *sk, str= uct socket *parent) sksec->sclass =3D isec->sclass; } =20 -/* Called whenever SCTP receives an INIT chunk. This happens when an incom= ing - * connect(2), sctp_connectx(3) or sctp_sendmsg(3) (with no association - * already present). +/* + * Determines peer_secid for the asoc and updates socket's peer label + * if it's the first association on the socket. */ -static int selinux_sctp_assoc_request(struct sctp_association *asoc, - struct sk_buff *skb) +static int selinux_sctp_process_new_assoc(struct sctp_association *asoc, + struct sk_buff *skb) { - struct sk_security_struct *sksec =3D asoc->base.sk->sk_security; + struct sock *sk =3D asoc->base.sk; + u16 family =3D sk->sk_family; + struct sk_security_struct *sksec =3D sk->sk_security; struct common_audit_data ad; struct lsm_network_audit net =3D {0,}; - u8 peerlbl_active; - u32 peer_sid =3D SECINITSID_UNLABELED; - u32 conn_sid; - int err =3D 0; + int err; =20 - if (!selinux_policycap_extsockclass()) - return 0; + /* handle mapped IPv4 packets arriving via IPv6 sockets */ + if (family =3D=3D PF_INET6 && skb->protocol =3D=3D htons(ETH_P_IP)) + family =3D PF_INET; =20 - peerlbl_active =3D selinux_peerlbl_enabled(); + if (selinux_peerlbl_enabled()) { + asoc->peer_secid =3D SECSID_NULL; =20 - if (peerlbl_active) { /* This will return peer_sid =3D SECSID_NULL if there are * no peer labels, see security_net_peersid_resolve(). */ - err =3D selinux_skb_peerlbl_sid(skb, asoc->base.sk->sk_family, - &peer_sid); + err =3D selinux_skb_peerlbl_sid(skb, family, &asoc->peer_secid); if (err) return err; =20 - if (peer_sid =3D=3D SECSID_NULL) - peer_sid =3D SECINITSID_UNLABELED; + if (asoc->peer_secid =3D=3D SECSID_NULL) + asoc->peer_secid =3D SECINITSID_UNLABELED; + } else { + asoc->peer_secid =3D SECINITSID_UNLABELED; } =20 if (sksec->sctp_assoc_state =3D=3D SCTP_ASSOC_UNSET) { @@ -5389,8 +5402,8 @@ static int selinux_sctp_assoc_request(struct sctp_ass= ociation *asoc, * then it is approved by policy and used as the primary * peer SID for getpeercon(3). */ - sksec->peer_sid =3D peer_sid; - } else if (sksec->peer_sid !=3D peer_sid) { + sksec->peer_sid =3D asoc->peer_secid; + } else if (sksec->peer_sid !=3D asoc->peer_secid) { /* Other association peer SIDs are checked to enforce * consistency among the peer SIDs. */ @@ -5398,11 +5411,32 @@ static int selinux_sctp_assoc_request(struct sctp_a= ssociation *asoc, ad.u.net =3D &net; ad.u.net->sk =3D asoc->base.sk; err =3D avc_has_perm(&selinux_state, - sksec->peer_sid, peer_sid, sksec->sclass, - SCTP_SOCKET__ASSOCIATION, &ad); + sksec->peer_sid, asoc->peer_secid, + sksec->sclass, SCTP_SOCKET__ASSOCIATION, + &ad); if (err) return err; } + return 0; +} + +/* Called whenever SCTP receives an INIT or COOKIE ECHO chunk. This + * happens on an incoming connect(2), sctp_connectx(3) or + * sctp_sendmsg(3) (with no association already present). + */ +static int selinux_sctp_assoc_request(struct sctp_association *asoc, + struct sk_buff *skb) +{ + struct sk_security_struct *sksec =3D asoc->base.sk->sk_security; + u32 conn_sid; + int err; + + if (!selinux_policycap_extsockclass()) + return 0; + + err =3D selinux_sctp_process_new_assoc(asoc, skb); + if (err) + return err; =20 /* Compute the MLS component for the connection and store * the information in asoc. This will be used by SCTP TCP type @@ -5410,17 +5444,36 @@ static int selinux_sctp_assoc_request(struct sctp_a= ssociation *asoc, * socket to be generated. selinux_sctp_sk_clone() will then * plug this into the new socket. */ - err =3D selinux_conn_sid(sksec->sid, peer_sid, &conn_sid); + err =3D selinux_conn_sid(sksec->sid, asoc->peer_secid, &conn_sid); if (err) return err; =20 asoc->secid =3D conn_sid; - asoc->peer_secid =3D peer_sid; =20 /* Set any NetLabel labels including CIPSO/CALIPSO options. */ return selinux_netlbl_sctp_assoc_request(asoc, skb); } =20 +/* Called when SCTP receives a COOKIE ACK chunk as the final + * response to an association request (initited by us). + */ +static int selinux_sctp_assoc_established(struct sctp_association *asoc, + struct sk_buff *skb) +{ + struct sk_security_struct *sksec =3D asoc->base.sk->sk_security; + + if (!selinux_policycap_extsockclass()) + return 0; + + /* Inherit secid from the parent socket - this will be picked up + * by selinux_sctp_sk_clone() if the association gets peeled off + * into a new socket. + */ + asoc->secid =3D sksec->sid; + + return selinux_sctp_process_new_assoc(asoc, skb); +} + /* Check if sctp IPv4/IPv6 addresses are valid for binding or connecting * based on their @optname. */ @@ -7241,6 +7294,7 @@ static struct security_hook_list selinux_hooks[] __ls= m_ro_after_init =3D { LSM_HOOK_INIT(sctp_assoc_request, selinux_sctp_assoc_request), LSM_HOOK_INIT(sctp_sk_clone, selinux_sctp_sk_clone), LSM_HOOK_INIT(sctp_bind_connect, selinux_sctp_bind_connect), + LSM_HOOK_INIT(sctp_assoc_established, selinux_sctp_assoc_established), LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request), LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone), LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established), diff --git a/security/selinux/include/policycap.h b/security/selinux/includ= e/policycap.h index 2ec038efbb03..a9e572ca4fd9 100644 --- a/security/selinux/include/policycap.h +++ b/security/selinux/include/policycap.h @@ -11,6 +11,7 @@ enum { POLICYDB_CAPABILITY_CGROUPSECLABEL, POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION, POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS, + POLICYDB_CAPABILITY_IOCTL_SKIP_CLOEXEC, __POLICYDB_CAPABILITY_MAX }; #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1) diff --git a/security/selinux/include/policycap_names.h b/security/selinux/= include/policycap_names.h index b89289f092c9..ebd64afe1def 100644 --- a/security/selinux/include/policycap_names.h +++ b/security/selinux/include/policycap_names.h @@ -12,7 +12,8 @@ const char *selinux_policycap_names[__POLICYDB_CAPABILITY= _MAX] =3D { "always_check_network", "cgroup_seclabel", "nnp_nosuid_transition", - "genfs_seclabel_symlinks" + "genfs_seclabel_symlinks", + "ioctl_skip_cloexec" }; =20 #endif /* _SELINUX_POLICYCAP_NAMES_H_ */ diff --git a/security/selinux/include/security.h b/security/selinux/include= /security.h index ac0ece01305a..c0d966020ebd 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -219,6 +219,13 @@ static inline bool selinux_policycap_genfs_seclabel_sy= mlinks(void) return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_GENFS_SECLABEL_SYML= INKS]); } =20 +static inline bool selinux_policycap_ioctl_skip_cloexec(void) +{ + struct selinux_state *state =3D &selinux_state; + + return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_IOCTL_SKIP_CLOEXEC]= ); +} + struct selinux_policy_convert_data; =20 struct selinux_load_state { diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index e4cd7cb856f3..f2f6203e0fff 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -2127,6 +2127,8 @@ static int sel_fill_super(struct super_block *sb, str= uct fs_context *fc) } =20 ret =3D sel_make_avc_files(dentry); + if (ret) + goto err; =20 dentry =3D sel_make_dir(sb->s_root, "ss", &fsi->last_ino); if (IS_ERR(dentry)) { diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index be83e5ce4469..debe15207d2b 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -347,7 +347,7 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state = *x, int rc; struct xfrm_sec_ctx *ctx; char *ctx_str =3D NULL; - int str_len; + u32 str_len; =20 if (!polsec) return 0; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index efd35b07c7f8..95a15b77f42f 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -2511,7 +2511,7 @@ static int smk_ipv6_check(struct smack_known *subject, #ifdef CONFIG_AUDIT smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); ad.a.u.net->family =3D PF_INET6; - ad.a.u.net->dport =3D ntohs(address->sin6_port); + ad.a.u.net->dport =3D address->sin6_port; if (act =3D=3D SMK_RECEIVING) ad.a.u.net->v6info.saddr =3D address->sin6_addr; else diff --git a/security/tomoyo/load_policy.c b/security/tomoyo/load_policy.c index 3445ae6fd479..363b65be87ab 100644 --- a/security/tomoyo/load_policy.c +++ b/security/tomoyo/load_policy.c @@ -24,7 +24,7 @@ static const char *tomoyo_loader; static int __init tomoyo_loader_setup(char *str) { tomoyo_loader =3D str; - return 0; + return 1; } =20 __setup("TOMOYO_loader=3D", tomoyo_loader_setup); @@ -64,7 +64,7 @@ static const char *tomoyo_trigger; static int __init tomoyo_trigger_setup(char *str) { tomoyo_trigger =3D str; - return 0; + return 1; } =20 __setup("TOMOYO_trigger=3D", tomoyo_trigger_setup); diff --git a/sound/core/pcm.c b/sound/core/pcm.c index edd9849210f2..977d54320a5c 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -970,6 +970,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int s= tream, =20 runtime->status->state =3D SNDRV_PCM_STATE_OPEN; mutex_init(&runtime->buffer_mutex); + atomic_set(&runtime->buffer_accessing, 0); =20 substream->runtime =3D runtime; substream->private_data =3D pcm->private_data; diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 27ee0a0bee04..c363cd3fe1ed 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1906,11 +1906,9 @@ static int wait_for_avail(struct snd_pcm_substream *= substream, if (avail >=3D runtime->twake) break; snd_pcm_stream_unlock_irq(substream); - mutex_unlock(&runtime->buffer_mutex); =20 tout =3D schedule_timeout(wait_time); =20 - mutex_lock(&runtime->buffer_mutex); snd_pcm_stream_lock_irq(substream); set_current_state(TASK_INTERRUPTIBLE); switch (runtime->status->state) { @@ -2204,7 +2202,6 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_s= ubstream *substream, =20 nonblock =3D !!(substream->f_flags & O_NONBLOCK); =20 - mutex_lock(&runtime->buffer_mutex); snd_pcm_stream_lock_irq(substream); err =3D pcm_accessible_state(runtime); if (err < 0) @@ -2259,6 +2256,10 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_= substream *substream, err =3D -EINVAL; goto _end_unlock; } + if (!atomic_inc_unless_negative(&runtime->buffer_accessing)) { + err =3D -EBUSY; + goto _end_unlock; + } snd_pcm_stream_unlock_irq(substream); if (!is_playback) snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_CPU); @@ -2267,6 +2268,7 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_s= ubstream *substream, if (is_playback) snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); snd_pcm_stream_lock_irq(substream); + atomic_dec(&runtime->buffer_accessing); if (err < 0) goto _end_unlock; err =3D pcm_accessible_state(runtime); @@ -2296,7 +2298,6 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_s= ubstream *substream, if (xfer > 0 && err >=3D 0) snd_pcm_update_state(substream, runtime); snd_pcm_stream_unlock_irq(substream); - mutex_unlock(&runtime->buffer_mutex); return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; } EXPORT_SYMBOL(__snd_pcm_lib_xfer); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 3cfae44c6b72..d954d167db3c 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -672,6 +672,24 @@ static int snd_pcm_hw_params_choose(struct snd_pcm_sub= stream *pcm, return 0; } =20 +/* acquire buffer_mutex; if it's in r/w operation, return -EBUSY, otherwise + * block the further r/w operations + */ +static int snd_pcm_buffer_access_lock(struct snd_pcm_runtime *runtime) +{ + if (!atomic_dec_unless_positive(&runtime->buffer_accessing)) + return -EBUSY; + mutex_lock(&runtime->buffer_mutex); + return 0; /* keep buffer_mutex, unlocked by below */ +} + +/* release buffer_mutex and clear r/w access flag */ +static void snd_pcm_buffer_access_unlock(struct snd_pcm_runtime *runtime) +{ + mutex_unlock(&runtime->buffer_mutex); + atomic_inc(&runtime->buffer_accessing); +} + #if IS_ENABLED(CONFIG_SND_PCM_OSS) #define is_oss_stream(substream) ((substream)->oss.oss) #else @@ -682,14 +700,16 @@ static int snd_pcm_hw_params(struct snd_pcm_substream= *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime; - int err =3D 0, usecs; + int err, usecs; unsigned int bits; snd_pcm_uframes_t frames; =20 if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime =3D substream->runtime; - mutex_lock(&runtime->buffer_mutex); + err =3D snd_pcm_buffer_access_lock(runtime); + if (err < 0) + return err; snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_OPEN: @@ -807,7 +827,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *= substream, snd_pcm_lib_free_pages(substream); } unlock: - mutex_unlock(&runtime->buffer_mutex); + snd_pcm_buffer_access_unlock(runtime); return err; } =20 @@ -852,7 +872,9 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *su= bstream) if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime =3D substream->runtime; - mutex_lock(&runtime->buffer_mutex); + result =3D snd_pcm_buffer_access_lock(runtime); + if (result < 0) + return result; snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_SETUP: @@ -871,7 +893,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *su= bstream) snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); cpu_latency_qos_remove_request(&substream->latency_pm_qos_req); unlock: - mutex_unlock(&runtime->buffer_mutex); + snd_pcm_buffer_access_unlock(runtime); return result; } =20 @@ -1356,12 +1378,15 @@ static int snd_pcm_action_nonatomic(const struct ac= tion_ops *ops, =20 /* Guarantee the group members won't change during non-atomic action */ down_read(&snd_pcm_link_rwsem); - mutex_lock(&substream->runtime->buffer_mutex); + res =3D snd_pcm_buffer_access_lock(substream->runtime); + if (res < 0) + goto unlock; if (snd_pcm_stream_linked(substream)) res =3D snd_pcm_action_group(ops, substream, state, false); else res =3D snd_pcm_action_single(ops, substream, state); - mutex_unlock(&substream->runtime->buffer_mutex); + snd_pcm_buffer_access_unlock(substream->runtime); + unlock: up_read(&snd_pcm_link_rwsem); return res; } diff --git a/sound/firewire/fcp.c b/sound/firewire/fcp.c index bbfbebf4affb..df44dd5dc4b2 100644 --- a/sound/firewire/fcp.c +++ b/sound/firewire/fcp.c @@ -240,9 +240,7 @@ int fcp_avc_transaction(struct fw_unit *unit, t.response_match_bytes =3D response_match_bytes; t.state =3D STATE_PENDING; init_waitqueue_head(&t.wait); - - if (*(const u8 *)command =3D=3D 0x00 || *(const u8 *)command =3D=3D 0x03) - t.deferrable =3D true; + t.deferrable =3D (*(const u8 *)command =3D=3D 0x00 || *(const u8 *)comman= d =3D=3D 0x03); =20 spin_lock_irq(&transactions_lock); list_add_tail(&t.list, &transactions); diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index b6bdebd9ef27..10112e1bb25d 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -494,7 +494,7 @@ static int snd_cs423x_pnpbios_detect(struct pnp_dev *pd= ev, static int dev; int err; struct snd_card *card; - struct pnp_dev *cdev; + struct pnp_dev *cdev, *iter; char cid[PNP_ID_LEN]; =20 if (pnp_device_is_isapnp(pdev)) @@ -510,9 +510,11 @@ static int snd_cs423x_pnpbios_detect(struct pnp_dev *p= dev, strcpy(cid, pdev->id[0].id); cid[5] =3D '1'; cdev =3D NULL; - list_for_each_entry(cdev, &(pdev->protocol->devices), protocol_list) { - if (!strcmp(cdev->id[0].id, cid)) + list_for_each_entry(iter, &(pdev->protocol->devices), protocol_list) { + if (!strcmp(iter->id[0].id, cid)) { + cdev =3D iter; break; + } } err =3D snd_cs423x_card_new(&pdev->dev, dev, &card); if (err < 0) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 3b6f2aacda45..1ffd96fbf230 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2061,14 +2061,16 @@ static const struct hda_controller_ops pci_hda_ops = =3D { .position_check =3D azx_position_check, }; =20 +static DECLARE_BITMAP(probed_devs, SNDRV_CARDS); + static int azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { - static int dev; struct snd_card *card; struct hda_intel *hda; struct azx *chip; bool schedule_probe; + int dev; int err; =20 if (pci_match_id(driver_denylist, pci)) { @@ -2076,10 +2078,11 @@ static int azx_probe(struct pci_dev *pci, return -ENODEV; } =20 + dev =3D find_first_zero_bit(probed_devs, SNDRV_CARDS); if (dev >=3D SNDRV_CARDS) return -ENODEV; if (!enable[dev]) { - dev++; + set_bit(dev, probed_devs); return -ENOENT; } =20 @@ -2146,7 +2149,7 @@ static int azx_probe(struct pci_dev *pci, if (schedule_probe) schedule_delayed_work(&hda->probe_work, 0); =20 - dev++; + set_bit(dev, probed_devs); if (chip->disabled) complete_all(&hda->probe_wait); return 0; @@ -2369,6 +2372,7 @@ static void azx_remove(struct pci_dev *pci) cancel_delayed_work_sync(&hda->probe_work); device_lock(&pci->dev); =20 + clear_bit(chip->dev_index, probed_devs); pci_set_drvdata(pci, NULL); snd_card_free(card); } diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index ffcde7409d2a..472d81679a27 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1617,6 +1617,7 @@ static void hdmi_present_sense_via_verbs(struct hdmi_= spec_per_pin *per_pin, struct hda_codec *codec =3D per_pin->codec; struct hdmi_spec *spec =3D codec->spec; struct hdmi_eld *eld =3D &spec->temp_eld; + struct device *dev =3D hda_codec_dev(codec); hda_nid_t pin_nid =3D per_pin->pin_nid; int dev_id =3D per_pin->dev_id; /* @@ -1630,8 +1631,13 @@ static void hdmi_present_sense_via_verbs(struct hdmi= _spec_per_pin *per_pin, int present; int ret; =20 +#ifdef CONFIG_PM + if (dev->power.runtime_status =3D=3D RPM_SUSPENDING) + return; +#endif + ret =3D snd_hda_power_up_pm(codec); - if (ret < 0 && pm_runtime_suspended(hda_codec_dev(codec))) + if (ret < 0 && pm_runtime_suspended(dev)) goto out; =20 present =3D snd_hda_jack_pin_sense(codec, pin_nid, dev_id); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 08bf8a77a3e4..f6e5ed34dd09 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3612,8 +3612,8 @@ static void alc256_shutup(struct hda_codec *codec) /* If disable 3k pulldown control for alc257, the Mic detection will not = work correctly * when booting with headset plugged. So skip setting it for the codec al= c257 */ - if (spec->codec_variant !=3D ALC269_TYPE_ALC257 && - spec->codec_variant !=3D ALC269_TYPE_ALC256) + if (codec->core.vendor_id !=3D 0x10ec0236 && + codec->core.vendor_id !=3D 0x10ec0257) alc_update_coef_idx(codec, 0x46, 0, 3 << 12); =20 if (!spec->no_shutup_pins) @@ -6816,6 +6816,7 @@ enum { ALC236_FIXUP_HP_MUTE_LED, ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF, ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, + ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, ALC295_FIXUP_ASUS_MIC_NO_PRESENCE, ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS, ALC269VC_FIXUP_ACER_HEADSET_MIC, @@ -8138,6 +8139,14 @@ static const struct hda_fixup alc269_fixups[] =3D { { } }, }, + [ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET] =3D { + .type =3D HDA_FIXUP_VERBS, + .v.verbs =3D (const struct hda_verb[]) { + { 0x20, AC_VERB_SET_COEF_INDEX, 0x08}, + { 0x20, AC_VERB_SET_PROC_COEF, 0x2fcf}, + { } + }, + }, [ALC295_FIXUP_ASUS_MIC_NO_PRESENCE] =3D { .type =3D HDA_FIXUP_PINS, .v.pins =3D (const struct hda_pintbl[]) { @@ -8900,6 +8909,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = =3D { SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FI= XUP_ATIV_BOOK_8), SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", AL= C298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)",= ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), + SND_PCI_QUIRK(0x144d, 0xc832, "Samsung Galaxy Book Flex Alpha (NP730QCJ)"= , ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_= MIC), SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MI= C), SND_PCI_QUIRK(0x1462, 0xb171, "Cubi N 8GL (MS-B171)", ALC283_FIXUP_HEADSE= T_MIC), @@ -9242,6 +9252,7 @@ static const struct hda_model_fixup alc269_fixup_mode= ls[] =3D { {.id =3D ALC298_FIXUP_HUAWEI_MBX_STEREO, .name =3D "huawei-mbx-stereo"}, {.id =3D ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE, .name =3D "alc256-medio= n-headset"}, {.id =3D ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name =3D "alc298-sam= sung-headphone"}, + {.id =3D ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name =3D "alc256-sam= sung-headphone"}, {.id =3D ALC255_FIXUP_XIAOMI_HEADSET_MIC, .name =3D "alc255-xiaomi-headse= t"}, {.id =3D ALC274_FIXUP_HP_MIC, .name =3D "alc274-hp-mic-detect"}, {.id =3D ALC245_FIXUP_HP_X360_AMP, .name =3D "alc245-hp-x360-amp"}, diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-ma= ch-common.c index 7785f12aa006..55ad3c70f0ef 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -531,6 +531,8 @@ int acp_legacy_dai_links_create(struct snd_soc_card *ca= rd) num_links++; =20 links =3D devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * num_links, = GFP_KERNEL); + if (!links) + return -ENOMEM; =20 if (drv_data->hs_cpu_id =3D=3D I2S_SP) { links[i].name =3D "acp-headset-codec"; diff --git a/sound/soc/amd/vangogh/acp5x-mach.c b/sound/soc/amd/vangogh/acp= 5x-mach.c index 14cf325e4b23..5d7a17755fa7 100644 --- a/sound/soc/amd/vangogh/acp5x-mach.c +++ b/sound/soc/amd/vangogh/acp5x-mach.c @@ -165,6 +165,7 @@ static int acp5x_cs35l41_hw_params(struct snd_pcm_subst= ream *substream, unsigned int num_codecs =3D rtd->num_codecs; unsigned int bclk_val; =20 + ret =3D 0; for (i =3D 0; i < num_codecs; i++) { codec_dai =3D asoc_rtd_to_codec(rtd, i); if ((strcmp(codec_dai->name, "spi-VLV1776:00") =3D=3D 0) || diff --git a/sound/soc/amd/vangogh/acp5x-pcm-dma.c b/sound/soc/amd/vangogh/= acp5x-pcm-dma.c index f10de38976cb..bfca4cf423cf 100644 --- a/sound/soc/amd/vangogh/acp5x-pcm-dma.c +++ b/sound/soc/amd/vangogh/acp5x-pcm-dma.c @@ -281,7 +281,7 @@ static int acp5x_dma_hw_params(struct snd_soc_component= *component, return -EINVAL; } size =3D params_buffer_bytes(params); - rtd->dma_addr =3D substream->dma_buffer.addr; + rtd->dma_addr =3D substream->runtime->dma_addr; rtd->num_pages =3D (PAGE_ALIGN(size) >> PAGE_SHIFT); config_acp5x_dma(rtd, substream->stream); return 0; @@ -426,51 +426,51 @@ static int acp5x_audio_remove(struct platform_device = *pdev) static int __maybe_unused acp5x_pcm_resume(struct device *dev) { struct i2s_dev_data *adata; - u32 val, reg_val, frmt_val; + struct i2s_stream_instance *rtd; + u32 val; =20 - reg_val =3D 0; - frmt_val =3D 0; adata =3D dev_get_drvdata(dev); =20 if (adata->play_stream && adata->play_stream->runtime) { - struct i2s_stream_instance *rtd =3D - adata->play_stream->runtime->private_data; + rtd =3D adata->play_stream->runtime->private_data; config_acp5x_dma(rtd, SNDRV_PCM_STREAM_PLAYBACK); - switch (rtd->i2s_instance) { - case I2S_HS_INSTANCE: - reg_val =3D ACP_HSTDM_ITER; - frmt_val =3D ACP_HSTDM_TXFRMT; - break; - case I2S_SP_INSTANCE: - default: - reg_val =3D ACP_I2STDM_ITER; - frmt_val =3D ACP_I2STDM_TXFRMT; + acp_writel((rtd->xfer_resolution << 3), rtd->acp5x_base + ACP_HSTDM_ITE= R); + if (adata->tdm_mode =3D=3D TDM_ENABLE) { + acp_writel(adata->tdm_fmt, adata->acp5x_base + ACP_HSTDM_TXFRMT); + val =3D acp_readl(adata->acp5x_base + ACP_HSTDM_ITER); + acp_writel(val | 0x2, adata->acp5x_base + ACP_HSTDM_ITER); + } + } + if (adata->i2ssp_play_stream && adata->i2ssp_play_stream->runtime) { + rtd =3D adata->i2ssp_play_stream->runtime->private_data; + config_acp5x_dma(rtd, SNDRV_PCM_STREAM_PLAYBACK); + acp_writel((rtd->xfer_resolution << 3), rtd->acp5x_base + ACP_I2STDM_IT= ER); + if (adata->tdm_mode =3D=3D TDM_ENABLE) { + acp_writel(adata->tdm_fmt, adata->acp5x_base + ACP_I2STDM_TXFRMT); + val =3D acp_readl(adata->acp5x_base + ACP_I2STDM_ITER); + acp_writel(val | 0x2, adata->acp5x_base + ACP_I2STDM_ITER); } - acp_writel((rtd->xfer_resolution << 3), - rtd->acp5x_base + reg_val); } =20 if (adata->capture_stream && adata->capture_stream->runtime) { - struct i2s_stream_instance *rtd =3D - adata->capture_stream->runtime->private_data; + rtd =3D adata->capture_stream->runtime->private_data; config_acp5x_dma(rtd, SNDRV_PCM_STREAM_CAPTURE); - switch (rtd->i2s_instance) { - case I2S_HS_INSTANCE: - reg_val =3D ACP_HSTDM_IRER; - frmt_val =3D ACP_HSTDM_RXFRMT; - break; - case I2S_SP_INSTANCE: - default: - reg_val =3D ACP_I2STDM_IRER; - frmt_val =3D ACP_I2STDM_RXFRMT; + acp_writel((rtd->xfer_resolution << 3), rtd->acp5x_base + ACP_HSTDM_IRE= R); + if (adata->tdm_mode =3D=3D TDM_ENABLE) { + acp_writel(adata->tdm_fmt, adata->acp5x_base + ACP_HSTDM_RXFRMT); + val =3D acp_readl(adata->acp5x_base + ACP_HSTDM_IRER); + acp_writel(val | 0x2, adata->acp5x_base + ACP_HSTDM_IRER); } - acp_writel((rtd->xfer_resolution << 3), - rtd->acp5x_base + reg_val); } - if (adata->tdm_mode =3D=3D TDM_ENABLE) { - acp_writel(adata->tdm_fmt, adata->acp5x_base + frmt_val); - val =3D acp_readl(adata->acp5x_base + reg_val); - acp_writel(val | 0x2, adata->acp5x_base + reg_val); + if (adata->i2ssp_capture_stream && adata->i2ssp_capture_stream->runtime) { + rtd =3D adata->i2ssp_capture_stream->runtime->private_data; + config_acp5x_dma(rtd, SNDRV_PCM_STREAM_CAPTURE); + acp_writel((rtd->xfer_resolution << 3), rtd->acp5x_base + ACP_I2STDM_IR= ER); + if (adata->tdm_mode =3D=3D TDM_ENABLE) { + acp_writel(adata->tdm_fmt, adata->acp5x_base + ACP_I2STDM_RXFRMT); + val =3D acp_readl(adata->acp5x_base + ACP_I2STDM_IRER); + acp_writel(val | 0x2, adata->acp5x_base + ACP_I2STDM_IRER); + } } acp_writel(1, adata->acp5x_base + ACP_EXTERNAL_INTR_ENB); return 0; diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_da= i.c index 26e2bc690d86..c1dea8d62416 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -280,7 +280,10 @@ static int atmel_ssc_startup(struct snd_pcm_substream = *substream, =20 /* Enable PMC peripheral clock for this SSC */ pr_debug("atmel_ssc_dai: Starting clock\n"); - clk_enable(ssc_p->ssc->clk); + ret =3D clk_enable(ssc_p->ssc->clk); + if (ret) + return ret; + ssc_p->mck_rate =3D clk_get_rate(ssc_p->ssc->clk); =20 /* Reset the SSC unless initialized to keep it in a clean state */ diff --git a/sound/soc/atmel/mikroe-proto.c b/sound/soc/atmel/mikroe-proto.c index f9331f7e80fe..5b513ff7fe2d 100644 --- a/sound/soc/atmel/mikroe-proto.c +++ b/sound/soc/atmel/mikroe-proto.c @@ -115,7 +115,8 @@ static int snd_proto_probe(struct platform_device *pdev) cpu_np =3D of_parse_phandle(np, "i2s-controller", 0); if (!cpu_np) { dev_err(&pdev->dev, "i2s-controller missing\n"); - return -EINVAL; + ret =3D -EINVAL; + goto put_codec_node; } dai->cpus->of_node =3D cpu_np; dai->platforms->of_node =3D cpu_np; @@ -125,7 +126,8 @@ static int snd_proto_probe(struct platform_device *pdev) &bitclkmaster, &framemaster); if (bitclkmaster !=3D framemaster) { dev_err(&pdev->dev, "Must be the same bitclock and frame master\n"); - return -EINVAL; + ret =3D -EINVAL; + goto put_cpu_node; } if (bitclkmaster) { if (codec_np =3D=3D bitclkmaster) @@ -136,18 +138,20 @@ static int snd_proto_probe(struct platform_device *pd= ev) dai_fmt |=3D snd_soc_daifmt_parse_clock_provider_as_flag(np, NULL); } =20 - of_node_put(bitclkmaster); - of_node_put(framemaster); - dai->dai_fmt =3D dai_fmt; - - of_node_put(codec_np); - of_node_put(cpu_np); =20 + dai->dai_fmt =3D dai_fmt; ret =3D snd_soc_register_card(&snd_proto); if (ret && ret !=3D -EPROBE_DEFER) dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); =20 + +put_cpu_node: + of_node_put(bitclkmaster); + of_node_put(framemaster); + of_node_put(cpu_np); +put_codec_node: + of_node_put(codec_np); return ret; } =20 diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8= 731.c index 915da92e1ec8..33e43013ff77 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -214,6 +214,7 @@ static int at91sam9g20ek_audio_probe(struct platform_de= vice *pdev) cpu_np =3D of_parse_phandle(np, "atmel,ssc-controller", 0); if (!cpu_np) { dev_err(&pdev->dev, "dai and pcm info missing\n"); + of_node_put(codec_np); return -EINVAL; } at91sam9g20ek_dai.cpus->of_node =3D cpu_np; diff --git a/sound/soc/atmel/sam9x5_wm8731.c b/sound/soc/atmel/sam9x5_wm873= 1.c index 7c45dc4f8c1b..99310e40e7a6 100644 --- a/sound/soc/atmel/sam9x5_wm8731.c +++ b/sound/soc/atmel/sam9x5_wm8731.c @@ -142,7 +142,7 @@ static int sam9x5_wm8731_driver_probe(struct platform_d= evice *pdev) if (!cpu_np) { dev_err(&pdev->dev, "atmel,ssc-controller node missing\n"); ret =3D -EINVAL; - goto out; + goto out_put_codec_np; } dai->cpus->of_node =3D cpu_np; dai->platforms->of_node =3D cpu_np; @@ -153,12 +153,9 @@ static int sam9x5_wm8731_driver_probe(struct platform_= device *pdev) if (ret !=3D 0) { dev_err(&pdev->dev, "Failed to set SSC %d for audio: %d\n", ret, priv->ssc_id); - goto out; + goto out_put_cpu_np; } =20 - of_node_put(codec_np); - of_node_put(cpu_np); - ret =3D devm_snd_soc_register_card(&pdev->dev, card); if (ret) { dev_err(&pdev->dev, "Platform device allocation failed\n"); @@ -167,10 +164,14 @@ static int sam9x5_wm8731_driver_probe(struct platform= _device *pdev) =20 dev_dbg(&pdev->dev, "%s ok\n", __func__); =20 - return ret; + goto out_put_cpu_np; =20 out_put_audio: atmel_ssc_put_audio(priv->ssc_id); +out_put_cpu_np: + of_node_put(cpu_np); +out_put_codec_np: + of_node_put(codec_np); out: return ret; } diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3a610ba183ff..0d4e1fb9befc 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -707,6 +707,7 @@ config SND_SOC_CS4349 =20 config SND_SOC_CS47L15 tristate + depends on MFD_CS47L15 =20 config SND_SOC_CS47L24 tristate @@ -714,15 +715,19 @@ config SND_SOC_CS47L24 =20 config SND_SOC_CS47L35 tristate + depends on MFD_CS47L35 =20 config SND_SOC_CS47L85 tristate + depends on MFD_CS47L85 =20 config SND_SOC_CS47L90 tristate + depends on MFD_CS47L90 =20 config SND_SOC_CS47L92 tristate + depends on MFD_CS47L92 =20 # Cirrus Logic Quad-Channel ADC config SND_SOC_CS53L30 diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index 9c4d481f7614..8a2d0f9dd9a6 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -1071,8 +1071,8 @@ static int cs35l41_irq_gpio_config(struct cs35l41_pri= vate *cs35l41) =20 regmap_update_bits(cs35l41->regmap, CS35L41_GPIO2_CTRL1, CS35L41_GPIO_POL_MASK | CS35L41_GPIO_DIR_MASK, - irq_gpio_cfg1->irq_pol_inv << CS35L41_GPIO_POL_SHIFT | - !irq_gpio_cfg1->irq_out_en << CS35L41_GPIO_DIR_SHIFT); + irq_gpio_cfg2->irq_pol_inv << CS35L41_GPIO_POL_SHIFT | + !irq_gpio_cfg2->irq_out_en << CS35L41_GPIO_DIR_SHIFT); =20 regmap_update_bits(cs35l41->regmap, CS35L41_GPIO_PAD_CONTROL, CS35L41_GPIO1_CTRL_MASK | CS35L41_GPIO2_CTRL_MASK, @@ -1113,7 +1113,7 @@ static struct snd_soc_dai_driver cs35l41_dai[] =3D { .capture =3D { .stream_name =3D "AMP Capture", .channels_min =3D 1, - .channels_max =3D 8, + .channels_max =3D 4, .rates =3D SNDRV_PCM_RATE_KNOT, .formats =3D CS35L41_TX_FORMATS, }, diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index a63fba4e6c9c..eb170d106396 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -1630,7 +1630,11 @@ static irqreturn_t cs42l42_irq_thread(int irq, void = *data) =20 mutex_lock(&cs42l42->jack_detect_mutex); =20 - /* Check auto-detect status */ + /* + * Check auto-detect status. Don't assume a previous unplug event has + * cleared the flags. If the jack is unplugged and plugged during + * system suspend there won't have been an unplug event. + */ if ((~masks[5]) & irq_params_table[5].mask) { if (stickies[5] & CS42L42_HSDET_AUTO_DONE_MASK) { cs42l42_process_hs_type_detect(cs42l42); @@ -1638,11 +1642,15 @@ static irqreturn_t cs42l42_irq_thread(int irq, void= *data) case CS42L42_PLUG_CTIA: case CS42L42_PLUG_OMTP: snd_soc_jack_report(cs42l42->jack, SND_JACK_HEADSET, - SND_JACK_HEADSET); + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); break; case CS42L42_PLUG_HEADPHONE: snd_soc_jack_report(cs42l42->jack, SND_JACK_HEADPHONE, - SND_JACK_HEADPHONE); + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); break; default: break; diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-= macro.c index 6ffe88345de5..3a3dc0539d92 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -2039,6 +2039,10 @@ static int rx_macro_load_compander_coeff(struct snd_= soc_component *component, int i; int hph_pwr_mode; =20 + /* AUX does not have compander */ + if (comp =3D=3D INTERP_AUX) + return 0; + if (!rx->comp_enabled[comp]) return 0; =20 @@ -2268,7 +2272,7 @@ static int rx_macro_mux_get(struct snd_kcontrol *kcon= trol, struct snd_soc_component *component =3D snd_soc_dapm_to_component(widget-= >dapm); struct rx_macro *rx =3D snd_soc_component_get_drvdata(component); =20 - ucontrol->value.integer.value[0] =3D + ucontrol->value.enumerated.item[0] =3D rx->rx_port_value[widget->shift]; return 0; } @@ -2280,7 +2284,7 @@ static int rx_macro_mux_put(struct snd_kcontrol *kcon= trol, struct snd_soc_component *component =3D snd_soc_dapm_to_component(widget-= >dapm); struct soc_enum *e =3D (struct soc_enum *)kcontrol->private_value; struct snd_soc_dapm_update *update =3D NULL; - u32 rx_port_value =3D ucontrol->value.integer.value[0]; + u32 rx_port_value =3D ucontrol->value.enumerated.item[0]; u32 aif_rst; struct rx_macro *rx =3D snd_soc_component_get_drvdata(component); =20 @@ -2392,7 +2396,7 @@ static int rx_macro_get_hph_pwr_mode(struct snd_kcont= rol *kcontrol, struct snd_soc_component *component =3D snd_soc_kcontrol_component(kcontr= ol); struct rx_macro *rx =3D snd_soc_component_get_drvdata(component); =20 - ucontrol->value.integer.value[0] =3D rx->hph_pwr_mode; + ucontrol->value.enumerated.item[0] =3D rx->hph_pwr_mode; return 0; } =20 @@ -2402,7 +2406,7 @@ static int rx_macro_put_hph_pwr_mode(struct snd_kcont= rol *kcontrol, struct snd_soc_component *component =3D snd_soc_kcontrol_component(kcontr= ol); struct rx_macro *rx =3D snd_soc_component_get_drvdata(component); =20 - rx->hph_pwr_mode =3D ucontrol->value.integer.value[0]; + rx->hph_pwr_mode =3D ucontrol->value.enumerated.item[0]; return 0; } =20 @@ -3542,6 +3546,8 @@ static int rx_macro_probe(struct platform_device *pde= v) return PTR_ERR(base); =20 rx->regmap =3D devm_regmap_init_mmio(dev, base, &rx_regmap_config); + if (IS_ERR(rx->regmap)) + return PTR_ERR(rx->regmap); =20 dev_set_drvdata(dev, rx); =20 diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-= macro.c index a4c0a155af56..9c96ab1bf84f 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -1821,6 +1821,8 @@ static int tx_macro_probe(struct platform_device *pde= v) } =20 tx->regmap =3D devm_regmap_init_mmio(dev, base, &tx_regmap_config); + if (IS_ERR(tx->regmap)) + return PTR_ERR(tx->regmap); =20 dev_set_drvdata(dev, tx); =20 diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-= macro.c index 11147e35689b..e14c277e6a8b 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -780,7 +780,7 @@ static int va_macro_dec_mode_get(struct snd_kcontrol *k= control, struct soc_enum *e =3D (struct soc_enum *)kcontrol->private_value; int path =3D e->shift_l; =20 - ucontrol->value.integer.value[0] =3D va->dec_mode[path]; + ucontrol->value.enumerated.item[0] =3D va->dec_mode[path]; =20 return 0; } @@ -789,7 +789,7 @@ static int va_macro_dec_mode_put(struct snd_kcontrol *k= control, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *comp =3D snd_soc_kcontrol_component(kcontrol); - int value =3D ucontrol->value.integer.value[0]; + int value =3D ucontrol->value.enumerated.item[0]; struct soc_enum *e =3D (struct soc_enum *)kcontrol->private_value; int path =3D e->shift_l; struct va_macro *va =3D snd_soc_component_get_drvdata(comp); diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-ws= a-macro.c index 75baf8eb7029..69d2915f40d8 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -2405,6 +2405,8 @@ static int wsa_macro_probe(struct platform_device *pd= ev) return PTR_ERR(base); =20 wsa->regmap =3D devm_regmap_init_mmio(dev, base, &wsa_regmap_config); + if (IS_ERR(wsa->regmap)) + return PTR_ERR(wsa->regmap); =20 dev_set_drvdata(dev, wsa); =20 diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index 5ba5f876eab8..fd84780bf689 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include "max98927.h" diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm89= 16-wcd-analog.c index 3ddd822240e3..971b8360b5b1 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -1221,8 +1221,10 @@ static int pm8916_wcd_analog_spmi_probe(struct platf= orm_device *pdev) } =20 irq =3D platform_get_irq_byname(pdev, "mbhc_switch_int"); - if (irq < 0) - return irq; + if (irq < 0) { + ret =3D irq; + goto err_disable_clk; + } =20 ret =3D devm_request_threaded_irq(dev, irq, NULL, pm8916_mbhc_switch_irq_handler, @@ -1234,8 +1236,10 @@ static int pm8916_wcd_analog_spmi_probe(struct platf= orm_device *pdev) =20 if (priv->mbhc_btn_enabled) { irq =3D platform_get_irq_byname(pdev, "mbhc_but_press_det"); - if (irq < 0) - return irq; + if (irq < 0) { + ret =3D irq; + goto err_disable_clk; + } =20 ret =3D devm_request_threaded_irq(dev, irq, NULL, mbhc_btn_press_irq_handler, @@ -1246,8 +1250,10 @@ static int pm8916_wcd_analog_spmi_probe(struct platf= orm_device *pdev) dev_err(dev, "cannot request mbhc button press irq\n"); =20 irq =3D platform_get_irq_byname(pdev, "mbhc_but_rel_det"); - if (irq < 0) - return irq; + if (irq < 0) { + ret =3D irq; + goto err_disable_clk; + } =20 ret =3D devm_request_threaded_irq(dev, irq, NULL, mbhc_btn_release_irq_handler, @@ -1264,6 +1270,10 @@ static int pm8916_wcd_analog_spmi_probe(struct platf= orm_device *pdev) return devm_snd_soc_register_component(dev, &pm8916_wcd_analog, pm8916_wcd_analog_dai, ARRAY_SIZE(pm8916_wcd_analog_dai)); + +err_disable_clk: + clk_disable_unprepare(priv->mclk); + return ret; } =20 static int pm8916_wcd_analog_spmi_remove(struct platform_device *pdev) diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8= 916-wcd-digital.c index fcc10c8bc625..9ad7fc0baf07 100644 --- a/sound/soc/codecs/msm8916-wcd-digital.c +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -1201,7 +1201,7 @@ static int msm8916_wcd_digital_probe(struct platform_= device *pdev) ret =3D clk_prepare_enable(priv->mclk); if (ret < 0) { dev_err(dev, "failed to enable mclk %d\n", ret); - return ret; + goto err_clk; } =20 dev_set_drvdata(dev, priv); @@ -1209,6 +1209,9 @@ static int msm8916_wcd_digital_probe(struct platform_= device *pdev) return devm_snd_soc_register_component(dev, &msm8916_wcd_digital, msm8916_wcd_digital_dai, ARRAY_SIZE(msm8916_wcd_digital_dai)); +err_clk: + clk_disable_unprepare(priv->ahbclk); + return ret; } =20 static int msm8916_wcd_digital_remove(struct platform_device *pdev) diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c index 9b263a9a669d..4c7b5d940799 100644 --- a/sound/soc/codecs/mt6358.c +++ b/sound/soc/codecs/mt6358.c @@ -107,6 +107,7 @@ int mt6358_set_mtkaif_protocol(struct snd_soc_component= *cmpnt, priv->mtkaif_protocol =3D mtkaif_protocol; return 0; } +EXPORT_SYMBOL_GPL(mt6358_set_mtkaif_protocol); =20 static void playback_gpio_set(struct mt6358_priv *priv) { @@ -273,6 +274,7 @@ int mt6358_mtkaif_calibration_enable(struct snd_soc_com= ponent *cmpnt) 1 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT); return 0; } +EXPORT_SYMBOL_GPL(mt6358_mtkaif_calibration_enable); =20 int mt6358_mtkaif_calibration_disable(struct snd_soc_component *cmpnt) { @@ -296,6 +298,7 @@ int mt6358_mtkaif_calibration_disable(struct snd_soc_co= mponent *cmpnt) capture_gpio_reset(priv); return 0; } +EXPORT_SYMBOL_GPL(mt6358_mtkaif_calibration_disable); =20 int mt6358_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt, int phase_1, int phase_2) @@ -310,6 +313,7 @@ int mt6358_set_mtkaif_calibration_phase(struct snd_soc_= component *cmpnt, phase_2 << RG_AUD_PAD_TOP_PHASE_MODE2_SFT); return 0; } +EXPORT_SYMBOL_GPL(mt6358_set_mtkaif_calibration_phase); =20 /* dl pga gain */ enum { diff --git a/sound/soc/codecs/rk817_codec.c b/sound/soc/codecs/rk817_codec.c index 03f24edfe4f6..8fffe378618d 100644 --- a/sound/soc/codecs/rk817_codec.c +++ b/sound/soc/codecs/rk817_codec.c @@ -508,12 +508,14 @@ static int rk817_platform_probe(struct platform_devic= e *pdev) if (ret < 0) { dev_err(&pdev->dev, "%s() register codec error %d\n", __func__, ret); - goto err_; + goto err_clk; } =20 return 0; -err_: =20 +err_clk: + clk_disable_unprepare(rk817_codec_data->mclk); +err_: return ret; } =20 diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 2138f62e6af5..3a8fba101b20 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -3478,6 +3478,8 @@ static int rt5663_parse_dp(struct rt5663_priv *rt5663= , struct device *dev) table_size =3D sizeof(struct impedance_mapping_table) * rt5663->pdata.impedance_sensing_num; rt5663->imp_table =3D devm_kzalloc(dev, table_size, GFP_KERNEL); + if (!rt5663->imp_table) + return -ENOMEM; ret =3D device_property_read_u32_array(dev, "realtek,impedance_sensing_table", (u32 *)rt5663->imp_table, table_size); diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index d79b548d23fa..f2a2f3d60925 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -822,6 +822,7 @@ static void rt5682s_jack_detect_handler(struct work_str= uct *work) { struct rt5682s_priv *rt5682s =3D container_of(work, struct rt5682s_priv, jack_detect_work.work); + struct snd_soc_dapm_context *dapm; int val, btn_type; =20 if (!rt5682s->component || !rt5682s->component->card || @@ -832,7 +833,9 @@ static void rt5682s_jack_detect_handler(struct work_str= uct *work) return; } =20 - mutex_lock(&rt5682s->jdet_mutex); + dapm =3D snd_soc_component_get_dapm(rt5682s->component); + + snd_soc_dapm_mutex_lock(dapm); mutex_lock(&rt5682s->calibrate_mutex); =20 val =3D snd_soc_component_read(rt5682s->component, RT5682S_AJD1_CTRL) @@ -889,6 +892,9 @@ static void rt5682s_jack_detect_handler(struct work_str= uct *work) rt5682s->irq_work_delay_time =3D 50; } =20 + mutex_unlock(&rt5682s->calibrate_mutex); + snd_soc_dapm_mutex_unlock(dapm); + snd_soc_jack_report(rt5682s->hs_jack, rt5682s->jack_type, SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3); @@ -898,9 +904,6 @@ static void rt5682s_jack_detect_handler(struct work_str= uct *work) schedule_delayed_work(&rt5682s->jd_check_work, 0); else cancel_delayed_work_sync(&rt5682s->jd_check_work); - - mutex_unlock(&rt5682s->calibrate_mutex); - mutex_unlock(&rt5682s->jdet_mutex); } =20 static void rt5682s_jd_check_handler(struct work_struct *work) @@ -908,14 +911,9 @@ static void rt5682s_jd_check_handler(struct work_struc= t *work) struct rt5682s_priv *rt5682s =3D container_of(work, struct rt5682s_priv, jd_check_work.work); =20 - if (snd_soc_component_read(rt5682s->component, RT5682S_AJD1_CTRL) - & RT5682S_JDH_RS_MASK) { + if (snd_soc_component_read(rt5682s->component, RT5682S_AJD1_CTRL) & RT568= 2S_JDH_RS_MASK) { /* jack out */ - rt5682s->jack_type =3D rt5682s_headset_detect(rt5682s->component, 0); - - snd_soc_jack_report(rt5682s->hs_jack, rt5682s->jack_type, - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3); + schedule_delayed_work(&rt5682s->jack_detect_work, 0); } else { schedule_delayed_work(&rt5682s->jd_check_work, 500); } @@ -1323,7 +1321,6 @@ static int rt5682s_hp_amp_event(struct snd_soc_dapm_w= idget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *component =3D snd_soc_dapm_to_component(w->dapm= ); - struct rt5682s_priv *rt5682s =3D snd_soc_component_get_drvdata(component); =20 switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -1339,8 +1336,6 @@ static int rt5682s_hp_amp_event(struct snd_soc_dapm_w= idget *w, snd_soc_component_write(component, RT5682S_BIAS_CUR_CTRL_11, 0x6666); snd_soc_component_write(component, RT5682S_BIAS_CUR_CTRL_12, 0xa82a); =20 - mutex_lock(&rt5682s->jdet_mutex); - snd_soc_component_update_bits(component, RT5682S_HP_CTRL_2, RT5682S_HPO_L_PATH_MASK | RT5682S_HPO_R_PATH_MASK | RT5682S_HPO_SEL_IP_EN_SW, RT5682S_HPO_L_PATH_EN | @@ -1348,8 +1343,6 @@ static int rt5682s_hp_amp_event(struct snd_soc_dapm_w= idget *w, usleep_range(5000, 10000); snd_soc_component_update_bits(component, RT5682S_HP_AMP_DET_CTL_1, RT5682S_CP_SW_SIZE_MASK, RT5682S_CP_SW_SIZE_L | RT5682S_CP_SW_SIZE_S); - - mutex_unlock(&rt5682s->jdet_mutex); break; =20 case SND_SOC_DAPM_POST_PMD: @@ -3075,7 +3068,6 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c, =20 mutex_init(&rt5682s->calibrate_mutex); mutex_init(&rt5682s->sar_mutex); - mutex_init(&rt5682s->jdet_mutex); rt5682s_calibrate(rt5682s); =20 regmap_update_bits(rt5682s->regmap, RT5682S_MICBIAS_2, diff --git a/sound/soc/codecs/rt5682s.h b/sound/soc/codecs/rt5682s.h index 1bf2ef7ce578..397a2531b6f6 100644 --- a/sound/soc/codecs/rt5682s.h +++ b/sound/soc/codecs/rt5682s.h @@ -1446,7 +1446,6 @@ struct rt5682s_priv { struct delayed_work jd_check_work; struct mutex calibrate_mutex; struct mutex sar_mutex; - struct mutex jdet_mutex; =20 #ifdef CONFIG_COMMON_CLK struct clk_hw dai_clks_hw[RT5682S_DAI_NUM_CLKS]; diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index e63c6b723d76..7b99318070cf 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -3023,14 +3023,14 @@ static int wcd934x_hph_impedance_get(struct snd_kco= ntrol *kcontrol, return 0; } static const struct snd_kcontrol_new hph_type_detect_controls[] =3D { - SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0, + SOC_SINGLE_EXT("HPH Type", 0, 0, WCD_MBHC_HPH_STEREO, 0, wcd934x_get_hph_type, NULL), }; =20 static const struct snd_kcontrol_new impedance_detect_controls[] =3D { - SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0, + SOC_SINGLE_EXT("HPHL Impedance", 0, 0, INT_MAX, 0, wcd934x_hph_impedance_get, NULL), - SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0, + SOC_SINGLE_EXT("HPHR Impedance", 0, 1, INT_MAX, 0, wcd934x_hph_impedance_get, NULL), }; =20 @@ -3308,13 +3308,16 @@ static int wcd934x_rx_hph_mode_put(struct snd_kcont= rol *kc, =20 mode_val =3D ucontrol->value.enumerated.item[0]; =20 + if (mode_val =3D=3D wcd->hph_mode) + return 0; + if (mode_val =3D=3D 0) { dev_err(wcd->dev, "Invalid HPH Mode, default to ClSH HiFi\n"); mode_val =3D CLS_H_LOHIFI; } wcd->hph_mode =3D mode_val; =20 - return 0; + return 1; } =20 static int slim_rx_mux_get(struct snd_kcontrol *kc, @@ -5885,6 +5888,7 @@ static int wcd934x_codec_parse_data(struct wcd934x_co= dec *wcd) } =20 wcd->sidev =3D of_slim_get_device(wcd->sdev->ctrl, ifc_dev_np); + of_node_put(ifc_dev_np); if (!wcd->sidev) { dev_err(dev, "Unable to get SLIM Interface device\n"); return -EINVAL; diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index bbc261ab2025..4480c118ed5d 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -2504,7 +2504,7 @@ static int wcd938x_tx_mode_get(struct snd_kcontrol *k= control, struct soc_enum *e =3D (struct soc_enum *)kcontrol->private_value; int path =3D e->shift_l; =20 - ucontrol->value.integer.value[0] =3D wcd938x->tx_mode[path]; + ucontrol->value.enumerated.item[0] =3D wcd938x->tx_mode[path]; =20 return 0; } @@ -2528,7 +2528,7 @@ static int wcd938x_rx_hph_mode_get(struct snd_kcontro= l *kcontrol, struct snd_soc_component *component =3D snd_soc_kcontrol_component(kcontr= ol); struct wcd938x_priv *wcd938x =3D snd_soc_component_get_drvdata(component); =20 - ucontrol->value.integer.value[0] =3D wcd938x->hph_mode; + ucontrol->value.enumerated.item[0] =3D wcd938x->hph_mode; =20 return 0; } @@ -3577,14 +3577,14 @@ static int wcd938x_hph_impedance_get(struct snd_kco= ntrol *kcontrol, } =20 static const struct snd_kcontrol_new hph_type_detect_controls[] =3D { - SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0, + SOC_SINGLE_EXT("HPH Type", 0, 0, WCD_MBHC_HPH_STEREO, 0, wcd938x_get_hph_type, NULL), }; =20 static const struct snd_kcontrol_new impedance_detect_controls[] =3D { - SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0, + SOC_SINGLE_EXT("HPHL Impedance", 0, 0, INT_MAX, 0, wcd938x_hph_impedance_get, NULL), - SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0, + SOC_SINGLE_EXT("HPHR Impedance", 0, 1, INT_MAX, 0, wcd938x_hph_impedance_get, NULL), }; =20 diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 15d42ce3b21d..41504ce2a682 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1537,18 +1537,38 @@ static int wm8350_component_probe(struct snd_soc_c= omponent *component) wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, WM8350_JDL_ENA | WM8350_JDR_ENA); =20 - wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, + ret =3D wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, wm8350_hpl_jack_handler, 0, "Left jack detect", priv); - wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, + if (ret !=3D 0) + goto err; + + ret =3D wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, wm8350_hpr_jack_handler, 0, "Right jack detect", priv); - wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICSCD, + if (ret !=3D 0) + goto free_jck_det_l; + + ret =3D wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICSCD, wm8350_mic_handler, 0, "Microphone short", priv); - wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD, + if (ret !=3D 0) + goto free_jck_det_r; + + ret =3D wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD, wm8350_mic_handler, 0, "Microphone detect", priv); + if (ret !=3D 0) + goto free_micscd; =20 return 0; + +free_micscd: + wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_MICSCD, priv); +free_jck_det_r: + wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, priv); +free_jck_det_l: + wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, priv); +err: + return ret; } =20 static void wm8350_component_remove(struct snd_soc_component *component) diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index 5cb58929090d..1edac3e10f34 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -403,9 +403,13 @@ static int dw_i2s_runtime_suspend(struct device *dev) static int dw_i2s_runtime_resume(struct device *dev) { struct dw_i2s_dev *dw_dev =3D dev_get_drvdata(dev); + int ret; =20 - if (dw_dev->capability & DW_I2S_MASTER) - clk_enable(dw_dev->clk); + if (dw_dev->capability & DW_I2S_MASTER) { + ret =3D clk_enable(dw_dev->clk); + if (ret) + return ret; + } return 0; } =20 @@ -422,10 +426,13 @@ static int dw_i2s_resume(struct snd_soc_component *co= mponent) { struct dw_i2s_dev *dev =3D snd_soc_component_get_drvdata(component); struct snd_soc_dai *dai; - int stream; + int stream, ret; =20 - if (dev->capability & DW_I2S_MASTER) - clk_enable(dev->clk); + if (dev->capability & DW_I2S_MASTER) { + ret =3D clk_enable(dev->clk); + if (ret) + return ret; + } =20 for_each_component_dais(component, dai) { for_each_pcm_streams(stream) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index d178b479c8bd..06d4a014f296 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -610,6 +610,8 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream= *substream, mask =3D SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK | SCR_TXSEL_MASK | SCR_USRC_SEL_MASK | SCR_TXFIFO_FSEL_MASK; + /* Disable TX clock */ + regmap_update_bits(regmap, REG_SPDIF_STC, STC_TXCLK_ALL_EN_MASK, 0); } else { scr =3D SCR_RXFIFO_OFF | SCR_RXFIFO_CTL_ZERO; mask =3D SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK| diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c index 09c674ee79f1..168973035e35 100644 --- a/sound/soc/fsl/imx-es8328.c +++ b/sound/soc/fsl/imx-es8328.c @@ -87,6 +87,7 @@ static int imx_es8328_probe(struct platform_device *pdev) if (int_port > MUX_PORT_MAX || int_port =3D=3D 0) { dev_err(dev, "mux-int-port: hardware only has %d mux ports\n", MUX_PORT_MAX); + ret =3D -EINVAL; goto fail; } =20 diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simp= le-card-utils.c index 850e968677f1..7d8c9843ad53 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -275,6 +275,7 @@ int asoc_simple_hw_params(struct snd_pcm_substream *sub= stream, mclk_fs =3D props->mclk_fs; =20 if (mclk_fs) { + struct snd_soc_component *component; mclk =3D params_rate(params) * mclk_fs; =20 for_each_prop_dai_codec(props, i, pdai) { @@ -282,16 +283,30 @@ int asoc_simple_hw_params(struct snd_pcm_substream *s= ubstream, if (ret < 0) return ret; } + for_each_prop_dai_cpu(props, i, pdai) { ret =3D asoc_simple_set_clk_rate(pdai, mclk); if (ret < 0) return ret; } + + /* Ensure sysclk is set on all components in case any + * (such as platform components) are missed by calls to + * snd_soc_dai_set_sysclk. + */ + for_each_rtd_components(rtd, i, component) { + ret =3D snd_soc_component_set_sysclk(component, 0, 0, + mclk, SND_SOC_CLOCK_IN); + if (ret && ret !=3D -ENOTSUPP) + return ret; + } + for_each_rtd_codec_dais(rtd, i, sdai) { ret =3D snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_IN); if (ret && ret !=3D -ENOTSUPP) return ret; } + for_each_rtd_cpu_dais(rtd, i, sdai) { ret =3D snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_OUT); if (ret && ret !=3D -ENOTSUPP) diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/s= of_es8336.c index 20d577eaab6d..28d7670b8f8f 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -63,7 +63,12 @@ static const struct acpi_gpio_mapping *gpio_mapping =3D = acpi_es8336_gpios; =20 static void log_quirks(struct device *dev) { - dev_info(dev, "quirk SSP%ld", SOF_ES8336_SSP_CODEC(quirk)); + dev_info(dev, "quirk mask %#lx\n", quirk); + dev_info(dev, "quirk SSP%ld\n", SOF_ES8336_SSP_CODEC(quirk)); + if (quirk & SOF_ES8336_ENABLE_DMIC) + dev_info(dev, "quirk DMIC enabled\n"); + if (quirk & SOF_ES8336_TGL_GPIO_QUIRK) + dev_info(dev, "quirk TGL GPIO enabled\n"); } =20 static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_= sdw.c index 54eefaff62a7..182e23bc2f34 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -184,7 +184,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[]= =3D { .callback =3D sof_sdw_quirk_cb, .matches =3D { DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Convertible"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Conv"), }, .driver_data =3D (void *)(SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC | diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/= intel/common/soc-acpi-intel-bxt-match.c index 342d34052204..04a92e74d99b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c @@ -41,6 +41,11 @@ static struct snd_soc_acpi_mach *apl_quirk(void *arg) return mach; } =20 +static const struct snd_soc_acpi_codecs essx_83x6 =3D { + .num_codecs =3D 3, + .codecs =3D { "ESSX8316", "ESSX8326", "ESSX8336"}, +}; + static const struct snd_soc_acpi_codecs bxt_codecs =3D { .num_codecs =3D 1, .codecs =3D {"MX98357A"} @@ -83,7 +88,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[= ] =3D { .sof_tplg_filename =3D "sof-apl-tdf8532.tplg", }, { - .id =3D "ESSX8336", + .comp_ids =3D &essx_83x6, .drv_name =3D "sof-essx8336", .sof_fw_filename =3D "sof-apl.ri", .sof_tplg_filename =3D "sof-apl-es8336.tplg", diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c b/sound/soc/= intel/common/soc-acpi-intel-cml-match.c index 4eebc79d4b48..14395833d89e 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c @@ -9,6 +9,11 @@ #include #include =20 +static const struct snd_soc_acpi_codecs essx_83x6 =3D { + .num_codecs =3D 3, + .codecs =3D { "ESSX8316", "ESSX8326", "ESSX8336"}, +}; + static const struct snd_soc_acpi_codecs rt1011_spk_codecs =3D { .num_codecs =3D 1, .codecs =3D {"10EC1011"} @@ -82,7 +87,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[= ] =3D { .sof_tplg_filename =3D "sof-cml-da7219-max98390.tplg", }, { - .id =3D "ESSX8336", + .comp_ids =3D &essx_83x6, .drv_name =3D "sof-essx8336", .sof_fw_filename =3D "sof-cml.ri", .sof_tplg_filename =3D "sof-cml-es8336.tplg", diff --git a/sound/soc/intel/common/soc-acpi-intel-glk-match.c b/sound/soc/= intel/common/soc-acpi-intel-glk-match.c index 8492b7e2a945..7aa6a870d5a5 100644 --- a/sound/soc/intel/common/soc-acpi-intel-glk-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-glk-match.c @@ -9,6 +9,11 @@ #include #include =20 +static const struct snd_soc_acpi_codecs essx_83x6 =3D { + .num_codecs =3D 3, + .codecs =3D { "ESSX8316", "ESSX8326", "ESSX8336"}, +}; + static const struct snd_soc_acpi_codecs glk_codecs =3D { .num_codecs =3D 1, .codecs =3D {"MX98357A"} @@ -58,7 +63,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[= ] =3D { .sof_tplg_filename =3D "sof-glk-cs42l42.tplg", }, { - .id =3D "ESSX8336", + .comp_ids =3D &essx_83x6, .drv_name =3D "sof-essx8336", .sof_fw_filename =3D "sof-glk.ri", .sof_tplg_filename =3D "sof-glk-es8336.tplg", diff --git a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c b/sound/soc/= intel/common/soc-acpi-intel-jsl-match.c index 278ec196da7b..9d0d0e1437a4 100644 --- a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c @@ -9,6 +9,11 @@ #include #include =20 +static const struct snd_soc_acpi_codecs essx_83x6 =3D { + .num_codecs =3D 3, + .codecs =3D { "ESSX8316", "ESSX8326", "ESSX8336"}, +}; + static const struct snd_soc_acpi_codecs jsl_7219_98373_codecs =3D { .num_codecs =3D 1, .codecs =3D {"MX98373"} @@ -87,7 +92,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[= ] =3D { .sof_tplg_filename =3D "sof-jsl-cs42l42-mx98360a.tplg", }, { - .id =3D "ESSX8336", + .comp_ids =3D &essx_83x6, .drv_name =3D "sof-essx8336", .sof_fw_filename =3D "sof-jsl.ri", .sof_tplg_filename =3D "sof-jsl-es8336.tplg", diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/= intel/common/soc-acpi-intel-tgl-match.c index da31bb3cca17..e2658bca6931 100644 --- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -10,6 +10,11 @@ #include #include "soc-acpi-intel-sdw-mockup-match.h" =20 +static const struct snd_soc_acpi_codecs essx_83x6 =3D { + .num_codecs =3D 3, + .codecs =3D { "ESSX8316", "ESSX8326", "ESSX8336"}, +}; + static const struct snd_soc_acpi_codecs tgl_codecs =3D { .num_codecs =3D 1, .codecs =3D {"MX98357A"} @@ -389,7 +394,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machine= s[] =3D { .sof_tplg_filename =3D "sof-tgl-rt1011-rt5682.tplg", }, { - .id =3D "ESSX8336", + .comp_ids =3D &essx_83x6, .drv_name =3D "sof-essx8336", .sof_fw_filename =3D "sof-tgl.ri", .sof_tplg_filename =3D "sof-tgl-es8336.tplg", diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc= /mediatek/mt8183/mt8183-da7219-max98357.c index bda103211e0b..0ab8b050b305 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -685,7 +685,6 @@ static int mt8183_da7219_max98357_dev_probe(struct plat= form_device *pdev) struct snd_soc_dai_link *dai_link; struct mt8183_da7219_max98357_priv *priv; struct pinctrl *pinctrl; - const struct of_device_id *match; int ret, i; =20 platform_node =3D of_parse_phandle(pdev->dev.of_node, @@ -695,11 +694,9 @@ static int mt8183_da7219_max98357_dev_probe(struct pla= tform_device *pdev) return -EINVAL; } =20 - match =3D of_match_device(pdev->dev.driver->of_match_table, &pdev->dev); - if (!match || !match->data) + card =3D (struct snd_soc_card *)of_device_get_match_data(&pdev->dev); + if (!card) return -EINVAL; - - card =3D (struct snd_soc_card *)match->data; card->dev =3D &pdev->dev; =20 hdmi_codec =3D of_parse_phandle(pdev->dev.of_node, diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/s= ound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index 9f0bf15fe465..8c81c5528f6e 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -637,7 +637,6 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platfor= m_device *pdev) struct device_node *platform_node, *ec_codec, *hdmi_codec; struct snd_soc_dai_link *dai_link; struct mt8183_mt6358_ts3a227_max98357_priv *priv; - const struct of_device_id *match; int ret, i; =20 platform_node =3D of_parse_phandle(pdev->dev.of_node, @@ -647,11 +646,9 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platfo= rm_device *pdev) return -EINVAL; } =20 - match =3D of_match_device(pdev->dev.driver->of_match_table, &pdev->dev); - if (!match || !match->data) + card =3D (struct snd_soc_card *)of_device_get_match_data(&pdev->dev); + if (!card) return -EINVAL; - - card =3D (struct snd_soc_card *)match->data; card->dev =3D &pdev->dev; =20 ec_codec =3D of_parse_phandle(pdev->dev.of_node, "mediatek,ec-codec", 0); diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/soun= d/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index 24a5d0adec1b..c1d225b49851 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -1106,7 +1106,6 @@ static int mt8192_mt6359_dev_probe(struct platform_de= vice *pdev) struct device_node *platform_node, *hdmi_codec; int ret, i; struct snd_soc_dai_link *dai_link; - const struct of_device_id *match; struct mt8192_mt6359_priv *priv; =20 platform_node =3D of_parse_phandle(pdev->dev.of_node, @@ -1116,11 +1115,11 @@ static int mt8192_mt6359_dev_probe(struct platform_= device *pdev) return -EINVAL; } =20 - match =3D of_match_device(pdev->dev.driver->of_match_table, &pdev->dev); - if (!match || !match->data) - return -EINVAL; - - card =3D (struct snd_soc_card *)match->data; + card =3D (struct snd_soc_card *)of_device_get_match_data(&pdev->dev); + if (!card) { + ret =3D -EINVAL; + goto put_platform_node; + } card->dev =3D &pdev->dev; =20 hdmi_codec =3D of_parse_phandle(pdev->dev.of_node, @@ -1162,20 +1161,24 @@ static int mt8192_mt6359_dev_probe(struct platform_= device *pdev) } =20 priv =3D devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; + if (!priv) { + ret =3D -ENOMEM; + goto put_hdmi_codec; + } snd_soc_card_set_drvdata(card, priv); =20 ret =3D mt8192_afe_gpio_init(&pdev->dev); if (ret) { dev_err(&pdev->dev, "init gpio error %d\n", ret); - return ret; + goto put_hdmi_codec; } =20 ret =3D devm_snd_soc_register_card(&pdev->dev, card); =20 - of_node_put(platform_node); +put_hdmi_codec: of_node_put(hdmi_codec); +put_platform_node: + of_node_put(platform_node); return ret; } =20 diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index 6a2d24d48964..879c1221a809 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -455,7 +455,10 @@ static int mxs_saif_hw_params(struct snd_pcm_substream= *substream, * basic clock which should be fast enough for the internal * logic. */ - clk_enable(saif->clk); + ret =3D clk_enable(saif->clk); + if (ret) + return ret; + ret =3D clk_set_rate(saif->clk, 24000000); clk_disable(saif->clk); if (ret) diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index a6407f4388de..fb721bc49949 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c @@ -118,6 +118,9 @@ static int mxs_sgtl5000_probe(struct platform_device *p= dev) codec_np =3D of_parse_phandle(np, "audio-codec", 0); if (!saif_np[0] || !saif_np[1] || !codec_np) { dev_err(&pdev->dev, "phandle missing or invalid\n"); + of_node_put(codec_np); + of_node_put(saif_np[0]); + of_node_put(saif_np[1]); return -EINVAL; } =20 diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchi= p_i2s.c index a6d7656c206e..4ce5d2579387 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -716,19 +716,23 @@ static int rockchip_i2s_probe(struct platform_device = *pdev) i2s->mclk =3D devm_clk_get(&pdev->dev, "i2s_clk"); if (IS_ERR(i2s->mclk)) { dev_err(&pdev->dev, "Can't retrieve i2s master clock\n"); - return PTR_ERR(i2s->mclk); + ret =3D PTR_ERR(i2s->mclk); + goto err_clk; } =20 regs =3D devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(regs)) - return PTR_ERR(regs); + if (IS_ERR(regs)) { + ret =3D PTR_ERR(regs); + goto err_clk; + } =20 i2s->regmap =3D devm_regmap_init_mmio(&pdev->dev, regs, &rockchip_i2s_regmap_config); if (IS_ERR(i2s->regmap)) { dev_err(&pdev->dev, "Failed to initialise managed register map\n"); - return PTR_ERR(i2s->regmap); + ret =3D PTR_ERR(i2s->regmap); + goto err_clk; } =20 i2s->bclk_ratio =3D 64; @@ -768,7 +772,8 @@ static int rockchip_i2s_probe(struct platform_device *p= dev) i2s_runtime_suspend(&pdev->dev); err_pm_disable: pm_runtime_disable(&pdev->dev); - +err_clk: + clk_disable_unprepare(i2s->hclk); return ret; } =20 diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/roc= kchip_i2s_tdm.c index 5f9cb5c4c7f0..98700e75b82a 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -469,14 +469,14 @@ static int rockchip_i2s_tdm_set_fmt(struct snd_soc_da= i *cpu_dai, txcr_val =3D I2S_TXCR_IBM_NORMAL; rxcr_val =3D I2S_RXCR_IBM_NORMAL; break; - case SND_SOC_DAIFMT_DSP_A: /* PCM no delay mode */ - txcr_val =3D I2S_TXCR_TFS_PCM; - rxcr_val =3D I2S_RXCR_TFS_PCM; - break; - case SND_SOC_DAIFMT_DSP_B: /* PCM delay 1 mode */ + case SND_SOC_DAIFMT_DSP_A: /* PCM delay 1 mode */ txcr_val =3D I2S_TXCR_TFS_PCM | I2S_TXCR_PBM_MODE(1); rxcr_val =3D I2S_RXCR_TFS_PCM | I2S_RXCR_PBM_MODE(1); break; + case SND_SOC_DAIFMT_DSP_B: /* PCM no delay mode */ + txcr_val =3D I2S_TXCR_TFS_PCM; + rxcr_val =3D I2S_RXCR_TFS_PCM; + break; default: ret =3D -EINVAL; goto err_pm_put; @@ -1738,7 +1738,7 @@ static int __maybe_unused rockchip_i2s_tdm_resume(str= uct device *dev) struct rk_i2s_tdm_dev *i2s_tdm =3D dev_get_drvdata(dev); int ret; =20 - ret =3D pm_runtime_get_sync(dev); + ret =3D pm_runtime_resume_and_get(dev); if (ret < 0) return ret; ret =3D regcache_sync(i2s_tdm->regmap); diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index cdf3b7f69ba7..e9a1eb6bdf66 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -816,14 +816,27 @@ static int fsi_clk_enable(struct device *dev, return ret; } =20 - clk_enable(clock->xck); - clk_enable(clock->ick); - clk_enable(clock->div); + ret =3D clk_enable(clock->xck); + if (ret) + goto err; + ret =3D clk_enable(clock->ick); + if (ret) + goto disable_xck; + ret =3D clk_enable(clock->div); + if (ret) + goto disable_ick; =20 clock->count++; } =20 return ret; + +disable_ick: + clk_disable(clock->ick); +disable_xck: + clk_disable(clock->xck); +err: + return ret; } =20 static int fsi_clk_disable(struct device *dev, diff --git a/sound/soc/sh/rz-ssi.c b/sound/soc/sh/rz-ssi.c index fa0cc08f70ec..16de2633a873 100644 --- a/sound/soc/sh/rz-ssi.c +++ b/sound/soc/sh/rz-ssi.c @@ -411,54 +411,56 @@ static int rz_ssi_pio_recv(struct rz_ssi_priv *ssi, s= truct rz_ssi_stream *strm) { struct snd_pcm_substream *substream =3D strm->substream; struct snd_pcm_runtime *runtime; + bool done =3D false; u16 *buf; int fifo_samples; int frames_left; - int samples =3D 0; + int samples; int i; =20 if (!rz_ssi_stream_is_valid(ssi, strm)) return -EINVAL; =20 runtime =3D substream->runtime; - /* frames left in this period */ - frames_left =3D runtime->period_size - (strm->buffer_pos % - runtime->period_size); - if (frames_left =3D=3D 0) - frames_left =3D runtime->period_size; =20 - /* Samples in RX FIFO */ - fifo_samples =3D (rz_ssi_reg_readl(ssi, SSIFSR) >> - SSIFSR_RDC_SHIFT) & SSIFSR_RDC_MASK; + while (!done) { + /* frames left in this period */ + frames_left =3D runtime->period_size - + (strm->buffer_pos % runtime->period_size); + if (!frames_left) + frames_left =3D runtime->period_size; + + /* Samples in RX FIFO */ + fifo_samples =3D (rz_ssi_reg_readl(ssi, SSIFSR) >> + SSIFSR_RDC_SHIFT) & SSIFSR_RDC_MASK; + + /* Only read full frames at a time */ + samples =3D 0; + while (frames_left && (fifo_samples >=3D runtime->channels)) { + samples +=3D runtime->channels; + fifo_samples -=3D runtime->channels; + frames_left--; + } =20 - /* Only read full frames at a time */ - while (frames_left && (fifo_samples >=3D runtime->channels)) { - samples +=3D runtime->channels; - fifo_samples -=3D runtime->channels; - frames_left--; - } + /* not enough samples yet */ + if (!samples) + break; =20 - /* not enough samples yet */ - if (samples =3D=3D 0) - return 0; + /* calculate new buffer index */ + buf =3D (u16 *)(runtime->dma_area); + buf +=3D strm->buffer_pos * runtime->channels; =20 - /* calculate new buffer index */ - buf =3D (u16 *)(runtime->dma_area); - buf +=3D strm->buffer_pos * runtime->channels; - - /* Note, only supports 16-bit samples */ - for (i =3D 0; i < samples; i++) - *buf++ =3D (u16)(rz_ssi_reg_readl(ssi, SSIFRDR) >> 16); + /* Note, only supports 16-bit samples */ + for (i =3D 0; i < samples; i++) + *buf++ =3D (u16)(rz_ssi_reg_readl(ssi, SSIFRDR) >> 16); =20 - rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0); - rz_ssi_pointer_update(strm, samples / runtime->channels); + rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0); + rz_ssi_pointer_update(strm, samples / runtime->channels); =20 - /* - * If we finished this period, but there are more samples in - * the RX FIFO, call this function again - */ - if (frames_left =3D=3D 0 && fifo_samples >=3D runtime->channels) - rz_ssi_pio_recv(ssi, strm); + /* check if there are no more samples in the RX FIFO */ + if (!(!frames_left && fifo_samples >=3D runtime->channels)) + done =3D true; + } =20 return 0; } @@ -975,6 +977,9 @@ static int rz_ssi_probe(struct platform_device *pdev) ssi->playback.priv =3D ssi; ssi->capture.priv =3D ssi; =20 + spin_lock_init(&ssi->lock); + dev_set_drvdata(&pdev->dev, ssi); + /* Error Interrupt */ ssi->irq_int =3D platform_get_irq_byname(pdev, "int_req"); if (ssi->irq_int < 0) @@ -1022,8 +1027,6 @@ static int rz_ssi_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_resume_and_get(&pdev->dev); =20 - spin_lock_init(&ssi->lock); - dev_set_drvdata(&pdev->dev, ssi); ret =3D devm_snd_soc_register_component(&pdev->dev, &rz_ssi_soc_component, rz_ssi_soc_dai, ARRAY_SIZE(rz_ssi_soc_dai)); diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 8e2494a9f3a7..e9dd25894dc0 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -567,6 +567,11 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *r= td, int num) return -EINVAL; } =20 + if (!codec_dai) { + dev_err(rtd->card->dev, "Missing codec\n"); + return -EINVAL; + } + /* check client and interface hw capabilities */ if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK)) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index dcf6be4c4aaa..0dc89f568407 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3184,7 +3184,7 @@ int snd_soc_get_dai_name(const struct of_phandle_args= *args, for_each_component(pos) { struct device_node *component_of_node =3D soc_component_to_node(pos); =20 - if (component_of_node !=3D args->np) + if (component_of_node !=3D args->np || !pos->num_dai) continue; =20 ret =3D snd_soc_component_of_xlate_dai_name(pos, args, dai_name); diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-= dmaengine-pcm.c index c54c8ca8d715..359987bf76d1 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -86,10 +86,10 @@ static int dmaengine_pcm_hw_params(struct snd_soc_compo= nent *component, =20 memset(&slave_config, 0, sizeof(slave_config)); =20 - if (!pcm->config) - prepare_slave_config =3D snd_dmaengine_pcm_prepare_slave_config; - else + if (pcm->config && pcm->config->prepare_slave_config) prepare_slave_config =3D pcm->config->prepare_slave_config; + else + prepare_slave_config =3D snd_dmaengine_pcm_prepare_slave_config; =20 if (prepare_slave_config) { int ret =3D prepare_slave_config(substream, params, &slave_config); diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index f5b9e66ac3b8..3bd0bba91600 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -512,7 +512,8 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tpl= g_ctl_hdr *hdr, =20 if (le32_to_cpu(hdr->ops.info) =3D=3D SND_SOC_TPLG_CTL_BYTES && k->iface & SNDRV_CTL_ELEM_IFACE_MIXER - && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE + && (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ + || k->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { struct soc_bytes_ext *sbe; struct snd_soc_tplg_bytes_control *be; diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index e4618980cf8b..1b20205ff0d1 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -192,6 +192,7 @@ static int imx8m_probe(struct snd_sof_dev *sdev) } =20 ret =3D of_address_to_resource(res_node, 0, &res); + of_node_put(res_node); if (ret) { dev_err(&pdev->dev, "failed to get reserved region address\n"); goto exit_pdev_unregister; diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 88b6176af021..d83e1a36707a 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -84,6 +84,7 @@ if SND_SOC_SOF_PCI config SND_SOC_SOF_MERRIFIELD tristate "SOF support for Tangier/Merrifield" default SND_SOC_SOF_PCI + select SND_SOC_SOF_PCI_DEV select SND_SOC_SOF_INTEL_ATOM_HIFI_EP help This adds support for Sound Open Firmware for Intel(R) platforms diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loa= der.c index abad6d0ceb83..635496306136 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -48,7 +48,7 @@ static struct hdac_ext_stream *cl_stream_prepare(struct s= nd_sof_dev *sdev, unsig ret =3D snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab); if (ret < 0) { dev_err(sdev->dev, "error: memory alloc failed: %d\n", ret); - goto error; + goto out_put; } =20 hstream->period_bytes =3D 0;/* initialize period_bytes */ @@ -59,22 +59,23 @@ static struct hdac_ext_stream *cl_stream_prepare(struct= snd_sof_dev *sdev, unsig ret =3D hda_dsp_iccmax_stream_hw_params(sdev, dsp_stream, dmab, NULL); if (ret < 0) { dev_err(sdev->dev, "error: iccmax stream prepare failed: %d\n", ret); - goto error; + goto out_free; } } else { ret =3D hda_dsp_stream_hw_params(sdev, dsp_stream, dmab, NULL); if (ret < 0) { dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret); - goto error; + goto out_free; } hda_dsp_stream_spib_config(sdev, dsp_stream, HDA_DSP_SPIB_ENABLE, size); } =20 return dsp_stream; =20 -error: - hda_dsp_stream_put(sdev, direction, hstream->stream_tag); +out_free: snd_dma_free_pages(dmab); +out_put: + hda_dsp_stream_put(sdev, direction, hstream->stream_tag); return ERR_PTR(ret); } =20 diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 41cb60955f5c..68834325d8fb 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -278,6 +278,7 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev, runtime->hw.info &=3D ~SNDRV_PCM_INFO_PAUSE; =20 if (hda_always_enable_dmi_l1 || + direction =3D=3D SNDRV_PCM_STREAM_PLAYBACK || spcm->stream[substream->stream].d0i3_compatible) flags |=3D SOF_HDA_STREAM_DMI_L1_COMPATIBLE; =20 diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 25200a0e1dc9..fc88296ab898 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1200,7 +1200,7 @@ static bool link_slaves_found(struct snd_sof_dev *sde= v, struct hdac_bus *bus =3D sof_to_bus(sdev); struct sdw_intel_slave_id *ids =3D sdw->ids; int num_slaves =3D sdw->num_slaves; - unsigned int part_id, link_id, unique_id, mfg_id; + unsigned int part_id, link_id, unique_id, mfg_id, version; int i, j, k; =20 for (i =3D 0; i < link->num_adr; i++) { @@ -1210,12 +1210,14 @@ static bool link_slaves_found(struct snd_sof_dev *s= dev, mfg_id =3D SDW_MFG_ID(adr); part_id =3D SDW_PART_ID(adr); link_id =3D SDW_DISCO_LINK_ID(adr); + version =3D SDW_VERSION(adr); =20 for (j =3D 0; j < num_slaves; j++) { /* find out how many identical parts were reported on that link */ if (ids[j].link_id =3D=3D link_id && ids[j].id.part_id =3D=3D part_id && - ids[j].id.mfg_id =3D=3D mfg_id) + ids[j].id.mfg_id =3D=3D mfg_id && + ids[j].id.sdw_version =3D=3D version) reported_part_count++; } =20 @@ -1224,21 +1226,24 @@ static bool link_slaves_found(struct snd_sof_dev *s= dev, =20 if (ids[j].link_id !=3D link_id || ids[j].id.part_id !=3D part_id || - ids[j].id.mfg_id !=3D mfg_id) + ids[j].id.mfg_id !=3D mfg_id || + ids[j].id.sdw_version !=3D version) continue; =20 /* find out how many identical parts are expected */ for (k =3D 0; k < link->num_adr; k++) { u64 adr2 =3D link->adr_d[k].adr; - unsigned int part_id2, link_id2, mfg_id2; + unsigned int part_id2, link_id2, mfg_id2, version2; =20 mfg_id2 =3D SDW_MFG_ID(adr2); part_id2 =3D SDW_PART_ID(adr2); link_id2 =3D SDW_DISCO_LINK_ID(adr2); + version2 =3D SDW_VERSION(adr2); =20 if (link_id2 =3D=3D link_id && part_id2 =3D=3D part_id && - mfg_id2 =3D=3D mfg_id) + mfg_id2 =3D=3D mfg_id && + version2 =3D=3D version) expected_part_count++; } =20 diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c index 6dca51862dd7..0363a088d2e0 100644 --- a/sound/soc/ti/davinci-i2s.c +++ b/sound/soc/ti/davinci-i2s.c @@ -708,7 +708,9 @@ static int davinci_i2s_probe(struct platform_device *pd= ev) dev->clk =3D clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) return -ENODEV; - clk_enable(dev->clk); + ret =3D clk_enable(dev->clk); + if (ret) + goto err_put_clk; =20 dev->dev =3D &pdev->dev; dev_set_drvdata(&pdev->dev, dev); @@ -730,6 +732,7 @@ static int davinci_i2s_probe(struct platform_device *pd= ev) snd_soc_unregister_component(&pdev->dev); err_release_clk: clk_disable(dev->clk); +err_put_clk: clk_put(dev->clk); return ret; } diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_= formatter_pcm.c index ce19a6058b27..5c4158069a5a 100644 --- a/sound/soc/xilinx/xlnx_formatter_pcm.c +++ b/sound/soc/xilinx/xlnx_formatter_pcm.c @@ -84,6 +84,7 @@ struct xlnx_pcm_drv_data { struct snd_pcm_substream *play_stream; struct snd_pcm_substream *capture_stream; struct clk *axi_clk; + unsigned int sysclk; }; =20 /* @@ -314,6 +315,15 @@ static irqreturn_t xlnx_s2mm_irq_handler(int irq, void= *arg) return IRQ_NONE; } =20 +static int xlnx_formatter_set_sysclk(struct snd_soc_component *component, + int clk_id, int source, unsigned int freq, int dir) +{ + struct xlnx_pcm_drv_data *adata =3D dev_get_drvdata(component->dev); + + adata->sysclk =3D freq; + return 0; +} + static int xlnx_formatter_pcm_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { @@ -450,11 +460,25 @@ static int xlnx_formatter_pcm_hw_params(struct snd_so= c_component *component, u64 size; struct snd_pcm_runtime *runtime =3D substream->runtime; struct xlnx_pcm_stream_param *stream_data =3D runtime->private_data; + struct xlnx_pcm_drv_data *adata =3D dev_get_drvdata(component->dev); =20 active_ch =3D params_channels(params); if (active_ch > stream_data->ch_limit) return -EINVAL; =20 + if (substream->stream =3D=3D SNDRV_PCM_STREAM_PLAYBACK && + adata->sysclk) { + unsigned int mclk_fs =3D adata->sysclk / params_rate(params); + + if (adata->sysclk % params_rate(params) !=3D 0) { + dev_warn(component->dev, "sysclk %u not divisible by rate %u\n", + adata->sysclk, params_rate(params)); + return -EINVAL; + } + + writel(mclk_fs, stream_data->mmio + XLNX_AUD_FS_MULTIPLIER); + } + if (substream->stream =3D=3D SNDRV_PCM_STREAM_CAPTURE && stream_data->xfer_mode =3D=3D AES_TO_PCM) { val =3D readl(stream_data->mmio + XLNX_AUD_STS); @@ -552,6 +576,7 @@ static int xlnx_formatter_pcm_new(struct snd_soc_compon= ent *component, =20 static const struct snd_soc_component_driver xlnx_asoc_component =3D { .name =3D DRV_NAME, + .set_sysclk =3D xlnx_formatter_set_sysclk, .open =3D xlnx_formatter_pcm_open, .close =3D xlnx_formatter_pcm_close, .hw_params =3D xlnx_formatter_pcm_hw_params, diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index 76c0e37a838c..8a2da6b1012e 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c @@ -218,7 +218,9 @@ static int snd_at73c213_pcm_open(struct snd_pcm_substre= am *substream) runtime->hw =3D snd_at73c213_playback_hw; chip->substream =3D substream; =20 - clk_enable(chip->ssc->clk); + err =3D clk_enable(chip->ssc->clk); + if (err) + return err; =20 return 0; } @@ -776,7 +778,9 @@ static int snd_at73c213_chip_init(struct snd_at73c213 *= chip) goto out; =20 /* Enable DAC master clock. */ - clk_enable(chip->board->dac_clk); + retval =3D clk_enable(chip->board->dac_clk); + if (retval) + goto out; =20 /* Initialize at73c213 on SPI bus. */ retval =3D snd_at73c213_write_reg(chip, DAC_RST, 0x04); @@ -889,7 +893,9 @@ static int snd_at73c213_dev_init(struct snd_card *card, chip->card =3D card; chip->irq =3D -1; =20 - clk_enable(chip->ssc->clk); + retval =3D clk_enable(chip->ssc->clk); + if (retval) + return retval; =20 retval =3D request_irq(irq, snd_at73c213_interrupt, 0, "at73c213", chip); if (retval) { @@ -1008,7 +1014,9 @@ static int snd_at73c213_remove(struct spi_device *spi) int retval; =20 /* Stop playback. */ - clk_enable(chip->ssc->clk); + retval =3D clk_enable(chip->ssc->clk); + if (retval) + goto out; ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS)); clk_disable(chip->ssc->clk); =20 @@ -1088,9 +1096,16 @@ static int snd_at73c213_resume(struct device *dev) { struct snd_card *card =3D dev_get_drvdata(dev); struct snd_at73c213 *chip =3D card->private_data; + int retval; =20 - clk_enable(chip->board->dac_clk); - clk_enable(chip->ssc->clk); + retval =3D clk_enable(chip->board->dac_clk); + if (retval) + return retval; + retval =3D clk_enable(chip->ssc->clk); + if (retval) { + clk_disable(chip->board->dac_clk); + return retval; + } ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXEN)); =20 return 0; diff --git a/tools/bpf/bpftool/btf.c b/tools/bpf/bpftool/btf.c index 015d2758f826..4a561ec848c0 100644 --- a/tools/bpf/bpftool/btf.c +++ b/tools/bpf/bpftool/btf.c @@ -899,7 +899,7 @@ static int do_show(int argc, char **argv) equal_fn_for_key_as_id, NULL); btf_map_table =3D hashmap__new(hash_fn_for_key_as_id, equal_fn_for_key_as_id, NULL); - if (!btf_prog_table || !btf_map_table) { + if (IS_ERR(btf_prog_table) || IS_ERR(btf_map_table)) { hashmap__free(btf_prog_table); hashmap__free(btf_map_table); if (fd >=3D 0) diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c index 5c18351290f0..587027050f43 100644 --- a/tools/bpf/bpftool/gen.c +++ b/tools/bpf/bpftool/gen.c @@ -928,7 +928,6 @@ static int do_skeleton(int argc, char **argv) s =3D (struct bpf_object_skeleton *)calloc(1, sizeof(*s));\n\ if (!s) \n\ goto err; \n\ - obj->skeleton =3D s; \n\ \n\ s->sz =3D sizeof(*s); \n\ s->name =3D \"%1$s\"; \n\ @@ -1001,6 +1000,7 @@ static int do_skeleton(int argc, char **argv) \n\ s->data =3D (void *)%2$s__elf_bytes(&s->data_sz); \n\ \n\ + obj->skeleton =3D s; \n\ return 0; \n\ err: \n\ bpf_object__destroy_skeleton(s); \n\ diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c index 2c258db0d352..97dec81950e5 100644 --- a/tools/bpf/bpftool/link.c +++ b/tools/bpf/bpftool/link.c @@ -2,6 +2,7 @@ /* Copyright (C) 2020 Facebook */ =20 #include +#include #include #include #include @@ -306,7 +307,7 @@ static int do_show(int argc, char **argv) if (show_pinned) { link_table =3D hashmap__new(hash_fn_for_key_as_id, equal_fn_for_key_as_id, NULL); - if (!link_table) { + if (IS_ERR(link_table)) { p_err("failed to create hashmap for pinned paths"); return -1; } diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index cae1f1119296..59d8e72851da 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c @@ -619,17 +619,14 @@ static int show_map_close_plain(int fd, struct bpf_ma= p_info *info) u32_as_hash_field(info->id)) printf("\n\tpinned %s", (char *)entry->value); } - printf("\n"); =20 if (frozen_str) { frozen =3D atoi(frozen_str); free(frozen_str); } =20 - if (!info->btf_id && !frozen) - return 0; - - printf("\t"); + if (info->btf_id || frozen) + printf("\n\t"); =20 if (info->btf_id) printf("btf_id %d", info->btf_id); @@ -698,7 +695,7 @@ static int do_show(int argc, char **argv) if (show_pinned) { map_table =3D hashmap__new(hash_fn_for_key_as_id, equal_fn_for_key_as_id, NULL); - if (!map_table) { + if (IS_ERR(map_table)) { p_err("failed to create hashmap for pinned paths"); return -1; } @@ -1053,11 +1050,9 @@ static void print_key_value(struct bpf_map_info *inf= o, void *key, json_writer_t *btf_wtr; struct btf *btf; =20 - btf =3D btf__load_from_kernel_by_id(info->btf_id); - if (libbpf_get_error(btf)) { - p_err("failed to get btf"); + btf =3D get_map_kv_btf(info); + if (libbpf_get_error(btf)) return; - } =20 if (json_output) { print_entry_json(info, key, value, btf); diff --git a/tools/bpf/bpftool/pids.c b/tools/bpf/bpftool/pids.c index 56b598eee043..7c384d10e95f 100644 --- a/tools/bpf/bpftool/pids.c +++ b/tools/bpf/bpftool/pids.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) /* Copyright (C) 2020 Facebook */ #include +#include #include #include #include @@ -101,7 +102,7 @@ int build_obj_refs_table(struct hashmap **map, enum bpf= _obj_type type) libbpf_print_fn_t default_print; =20 *map =3D hashmap__new(hash_fn_for_key_as_id, equal_fn_for_key_as_id, NULL= ); - if (!*map) { + if (IS_ERR(*map)) { p_err("failed to create hashmap for PID references"); return -1; } diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 6ccd17b8eb56..41ed566e8c73 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -571,7 +571,7 @@ static int do_show(int argc, char **argv) if (show_pinned) { prog_table =3D hashmap__new(hash_fn_for_key_as_id, equal_fn_for_key_as_id, NULL); - if (!prog_table) { + if (IS_ERR(prog_table)) { p_err("failed to create hashmap for pinned paths"); return -1; } diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index b12cfceddb6e..7faad2d5d05a 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -2284,8 +2284,8 @@ union bpf_attr { * Return * The return value depends on the result of the test, and can be: * - * * 0, if current task belongs to the cgroup2. - * * 1, if current task does not belong to the cgroup2. + * * 1, if current task belongs to the cgroup2. + * * 0, if current task does not belong to the cgroup2. * * A negative error code, if an error occurred. * * long bpf_skb_change_tail(struct sk_buff *skb, u32 len, u64 flags) diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h index 17c0a46d8cd2..fc393c4542e8 100644 --- a/tools/lib/bpf/btf.h +++ b/tools/lib/bpf/btf.h @@ -313,8 +313,28 @@ btf_dump__dump_type_data(struct btf_dump *d, __u32 id, const struct btf_dump_type_data_opts *opts); =20 /* - * A set of helpers for easier BTF types handling + * A set of helpers for easier BTF types handling. + * + * The inline functions below rely on constants from the kernel headers wh= ich + * may not be available for applications including this header file. To av= oid + * compilation errors, we define all the constants here that were added af= ter + * the initial introduction of the BTF_KIND* constants. */ +#ifndef BTF_KIND_FUNC +#define BTF_KIND_FUNC 12 /* Function */ +#define BTF_KIND_FUNC_PROTO 13 /* Function Proto */ +#endif +#ifndef BTF_KIND_VAR +#define BTF_KIND_VAR 14 /* Variable */ +#define BTF_KIND_DATASEC 15 /* Section */ +#endif +#ifndef BTF_KIND_FLOAT +#define BTF_KIND_FLOAT 16 /* Floating point */ +#endif +/* The kernel header switched to enums, so these two were never #defined */ +#define BTF_KIND_DECL_TAG 17 /* Decl Tag */ +#define BTF_KIND_TYPE_TAG 18 /* Type Tag */ + static inline __u16 btf_kind(const struct btf_type *t) { return BTF_INFO_KIND(t->info); diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c index 5cae71600631..96af8c4ecf78 100644 --- a/tools/lib/bpf/btf_dump.c +++ b/tools/lib/bpf/btf_dump.c @@ -1483,6 +1483,11 @@ static const char *btf_dump_resolve_name(struct btf_= dump *d, __u32 id, if (s->name_resolved) return *cached_name ? *cached_name : orig_name; =20 + if (btf_is_fwd(t) || (btf_is_enum(t) && btf_vlen(t) =3D=3D 0)) { + s->name_resolved =3D 1; + return orig_name; + } + dup_cnt =3D btf_dump_name_dups(d, name_map, orig_name); if (dup_cnt > 1) { const size_t max_len =3D 256; @@ -1839,14 +1844,16 @@ static int btf_dump_array_data(struct btf_dump *d, { const struct btf_array *array =3D btf_array(t); const struct btf_type *elem_type; - __u32 i, elem_size =3D 0, elem_type_id; + __u32 i, elem_type_id; + __s64 elem_size; bool is_array_member; =20 elem_type_id =3D array->type; elem_type =3D skip_mods_and_typedefs(d->btf, elem_type_id, NULL); elem_size =3D btf__resolve_size(d->btf, elem_type_id); if (elem_size <=3D 0) { - pr_warn("unexpected elem size %d for array type [%u]\n", elem_size, id); + pr_warn("unexpected elem size %zd for array type [%u]\n", + (ssize_t)elem_size, id); return -EINVAL; } =20 diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index c7ba5e6ed9cf..23edb41637d4 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -11497,6 +11497,9 @@ void bpf_object__detach_skeleton(struct bpf_object_= skeleton *s) =20 void bpf_object__destroy_skeleton(struct bpf_object_skeleton *s) { + if (!s) + return; + if (s->progs) bpf_object__detach_skeleton(s); if (s->obj) diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c index 39f25e09b51e..fadde7d80a51 100644 --- a/tools/lib/bpf/netlink.c +++ b/tools/lib/bpf/netlink.c @@ -87,29 +87,75 @@ enum { NL_DONE, }; =20 +static int netlink_recvmsg(int sock, struct msghdr *mhdr, int flags) +{ + int len; + + do { + len =3D recvmsg(sock, mhdr, flags); + } while (len < 0 && (errno =3D=3D EINTR || errno =3D=3D EAGAIN)); + + if (len < 0) + return -errno; + return len; +} + +static int alloc_iov(struct iovec *iov, int len) +{ + void *nbuf; + + nbuf =3D realloc(iov->iov_base, len); + if (!nbuf) + return -ENOMEM; + + iov->iov_base =3D nbuf; + iov->iov_len =3D len; + return 0; +} + static int libbpf_netlink_recv(int sock, __u32 nl_pid, int seq, __dump_nlmsg_t _fn, libbpf_dump_nlmsg_t fn, void *cookie) { + struct iovec iov =3D {}; + struct msghdr mhdr =3D { + .msg_iov =3D &iov, + .msg_iovlen =3D 1, + }; bool multipart =3D true; struct nlmsgerr *err; struct nlmsghdr *nh; - char buf[4096]; int len, ret; =20 + ret =3D alloc_iov(&iov, 4096); + if (ret) + goto done; + while (multipart) { start: multipart =3D false; - len =3D recv(sock, buf, sizeof(buf), 0); + len =3D netlink_recvmsg(sock, &mhdr, MSG_PEEK | MSG_TRUNC); + if (len < 0) { + ret =3D len; + goto done; + } + + if (len > iov.iov_len) { + ret =3D alloc_iov(&iov, len); + if (ret) + goto done; + } + + len =3D netlink_recvmsg(sock, &mhdr, 0); if (len < 0) { - ret =3D -errno; + ret =3D len; goto done; } =20 if (len =3D=3D 0) break; =20 - for (nh =3D (struct nlmsghdr *)buf; NLMSG_OK(nh, len); + for (nh =3D (struct nlmsghdr *)iov.iov_base; NLMSG_OK(nh, len); nh =3D NLMSG_NEXT(nh, len)) { if (nh->nlmsg_pid !=3D nl_pid) { ret =3D -LIBBPF_ERRNO__WRNGPID; @@ -130,7 +176,8 @@ static int libbpf_netlink_recv(int sock, __u32 nl_pid, = int seq, libbpf_nla_dump_errormsg(nh); goto done; case NLMSG_DONE: - return 0; + ret =3D 0; + goto done; default: break; } @@ -142,15 +189,17 @@ static int libbpf_netlink_recv(int sock, __u32 nl_pid= , int seq, case NL_NEXT: goto start; case NL_DONE: - return 0; + ret =3D 0; + goto done; default: - return ret; + goto done; } } } } ret =3D 0; done: + free(iov.iov_base); return ret; } =20 diff --git a/tools/lib/bpf/xsk.c b/tools/lib/bpf/xsk.c index 81f8fbc85e70..c43b4d94346d 100644 --- a/tools/lib/bpf/xsk.c +++ b/tools/lib/bpf/xsk.c @@ -1210,12 +1210,23 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr,= const char *ifname, =20 int xsk_umem__delete(struct xsk_umem *umem) { + struct xdp_mmap_offsets off; + int err; + if (!umem) return 0; =20 if (umem->refcount) return -EBUSY; =20 + err =3D xsk_get_mmap_offsets(umem->fd, &off); + if (!err && umem->fill_save && umem->comp_save) { + munmap(umem->fill_save->ring - off.fr.desc, + off.fr.desc + umem->config.fill_size * sizeof(__u64)); + munmap(umem->comp_save->ring - off.cr.desc, + off.cr.desc + umem->config.comp_size * sizeof(__u64)); + } + close(umem->fd); free(umem); =20 diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 7974933dbc77..08c024038ca7 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -956,10 +956,10 @@ static int __run_perf_stat(int argc, const char **arg= v, int run_idx) * Enable counters and exec the command: */ if (forks) { - evlist__start_workload(evsel_list); err =3D enable_counters(); if (err) return -1; + evlist__start_workload(evsel_list); =20 t0 =3D rdclock(); clock_gettime(CLOCK_MONOTONIC, &ref_time); diff --git a/tools/perf/pmu-events/arch/x86/skylakex/cache.json b/tools/per= f/pmu-events/arch/x86/skylakex/cache.json index 9ff67206ade4..821d2f2a8f25 100644 --- a/tools/perf/pmu-events/arch/x86/skylakex/cache.json +++ b/tools/perf/pmu-events/arch/x86/skylakex/cache.json @@ -314,6 +314,19 @@ "SampleAfterValue": "2000003", "UMask": "0x82" }, + { + "BriefDescription": "All retired memory instructions.", + "Counter": "0,1,2,3", + "CounterHTOff": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xD0", + "EventName": "MEM_INST_RETIRED.ANY", + "L1_Hit_Indication": "1", + "PEBS": "1", + "PublicDescription": "Counts all retired memory instructions - loa= ds and stores.", + "SampleAfterValue": "2000003", + "UMask": "0x83" + }, { "BriefDescription": "Retired load instructions with locked access.= ", "Counter": "0,1,2,3", @@ -358,6 +371,7 @@ "EventCode": "0xD0", "EventName": "MEM_INST_RETIRED.STLB_MISS_LOADS", "PEBS": "1", + "PublicDescription": "Number of retired load instructions that (st= art a) miss in the 2nd-level TLB (STLB).", "SampleAfterValue": "100003", "UMask": "0x11" }, @@ -370,6 +384,7 @@ "EventName": "MEM_INST_RETIRED.STLB_MISS_STORES", "L1_Hit_Indication": "1", "PEBS": "1", + "PublicDescription": "Number of retired store instructions that (s= tart a) miss in the 2nd-level TLB (STLB).", "SampleAfterValue": "100003", "UMask": "0x12" }, @@ -733,7 +748,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_DATA_RD.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0000010491", + "MSRValue": "0x10491", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -772,7 +787,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_DATA_RD.L3_HIT.HIT_OTHER_CORE_N= O_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x04003C0491", + "MSRValue": "0x4003C0491", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -785,7 +800,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_DATA_RD.L3_HIT.NO_SNOOP_NEEDED", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x01003C0491", + "MSRValue": "0x1003C0491", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -798,7 +813,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_DATA_RD.L3_HIT.SNOOP_HIT_WITH_F= WD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x08003C0491", + "MSRValue": "0x8003C0491", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -811,7 +826,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_PF_DATA_RD.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0000010490", + "MSRValue": "0x10490", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -850,7 +865,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_PF_DATA_RD.L3_HIT.HIT_OTHER_COR= E_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x04003C0490", + "MSRValue": "0x4003C0490", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -863,7 +878,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_PF_DATA_RD.L3_HIT.NO_SNOOP_NEED= ED", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x01003C0490", + "MSRValue": "0x1003C0490", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -876,7 +891,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_PF_DATA_RD.L3_HIT.SNOOP_HIT_WIT= H_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x08003C0490", + "MSRValue": "0x8003C0490", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -889,7 +904,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_PF_RFO.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0000010120", + "MSRValue": "0x10120", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -928,7 +943,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_PF_RFO.L3_HIT.HIT_OTHER_CORE_NO= _FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x04003C0120", + "MSRValue": "0x4003C0120", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -941,7 +956,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_PF_RFO.L3_HIT.NO_SNOOP_NEEDED", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x01003C0120", + "MSRValue": "0x1003C0120", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -954,7 +969,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_PF_RFO.L3_HIT.SNOOP_HIT_WITH_FW= D", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x08003C0120", + "MSRValue": "0x8003C0120", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -967,7 +982,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_RFO.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0000010122", + "MSRValue": "0x10122", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1006,7 +1021,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_RFO.L3_HIT.HIT_OTHER_CORE_NO_FW= D", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x04003C0122", + "MSRValue": "0x4003C0122", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1019,7 +1034,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_RFO.L3_HIT.NO_SNOOP_NEEDED", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x01003C0122", + "MSRValue": "0x1003C0122", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1032,7 +1047,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_RFO.L3_HIT.SNOOP_HIT_WITH_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x08003C0122", + "MSRValue": "0x8003C0122", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1045,7 +1060,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_CODE_RD.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0000010004", + "MSRValue": "0x10004", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1084,7 +1099,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_CODE_RD.L3_HIT.HIT_OTHER_COR= E_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x04003C0004", + "MSRValue": "0x4003C0004", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1097,7 +1112,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_CODE_RD.L3_HIT.NO_SNOOP_NEED= ED", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x01003C0004", + "MSRValue": "0x1003C0004", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1110,7 +1125,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_CODE_RD.L3_HIT.SNOOP_HIT_WIT= H_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x08003C0004", + "MSRValue": "0x8003C0004", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1123,7 +1138,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_DATA_RD.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0000010001", + "MSRValue": "0x10001", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1162,7 +1177,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_DATA_RD.L3_HIT.HIT_OTHER_COR= E_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x04003C0001", + "MSRValue": "0x4003C0001", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1175,7 +1190,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_DATA_RD.L3_HIT.NO_SNOOP_NEED= ED", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x01003C0001", + "MSRValue": "0x1003C0001", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1188,7 +1203,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_DATA_RD.L3_HIT.SNOOP_HIT_WIT= H_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x08003C0001", + "MSRValue": "0x8003C0001", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1201,7 +1216,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_RFO.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0000010002", + "MSRValue": "0x10002", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1240,7 +1255,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_RFO.L3_HIT.HIT_OTHER_CORE_NO= _FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x04003C0002", + "MSRValue": "0x4003C0002", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1253,7 +1268,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_RFO.L3_HIT.NO_SNOOP_NEEDED", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x01003C0002", + "MSRValue": "0x1003C0002", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1266,7 +1281,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_RFO.L3_HIT.SNOOP_HIT_WITH_FW= D", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x08003C0002", + "MSRValue": "0x8003C0002", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1279,7 +1294,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L1D_AND_SW.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0000010400", + "MSRValue": "0x10400", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1318,7 +1333,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L1D_AND_SW.L3_HIT.HIT_OTHER_CORE= _NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x04003C0400", + "MSRValue": "0x4003C0400", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1331,7 +1346,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L1D_AND_SW.L3_HIT.NO_SNOOP_NEEDE= D", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x01003C0400", + "MSRValue": "0x1003C0400", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1344,7 +1359,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L1D_AND_SW.L3_HIT.SNOOP_HIT_WITH= _FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x08003C0400", + "MSRValue": "0x8003C0400", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1357,7 +1372,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L2_DATA_RD.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0000010010", + "MSRValue": "0x10010", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1396,7 +1411,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L2_DATA_RD.L3_HIT.HIT_OTHER_CORE= _NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x04003C0010", + "MSRValue": "0x4003C0010", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1409,7 +1424,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L2_DATA_RD.L3_HIT.NO_SNOOP_NEEDE= D", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x01003C0010", + "MSRValue": "0x1003C0010", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1422,7 +1437,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L2_DATA_RD.L3_HIT.SNOOP_HIT_WITH= _FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x08003C0010", + "MSRValue": "0x8003C0010", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1435,7 +1450,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L2_RFO.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0000010020", + "MSRValue": "0x10020", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1474,7 +1489,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L2_RFO.L3_HIT.HIT_OTHER_CORE_NO_= FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x04003C0020", + "MSRValue": "0x4003C0020", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1487,7 +1502,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L2_RFO.L3_HIT.NO_SNOOP_NEEDED", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x01003C0020", + "MSRValue": "0x1003C0020", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1500,7 +1515,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L2_RFO.L3_HIT.SNOOP_HIT_WITH_FWD= ", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x08003C0020", + "MSRValue": "0x8003C0020", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1513,7 +1528,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L3_DATA_RD.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0000010080", + "MSRValue": "0x10080", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1552,7 +1567,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L3_DATA_RD.L3_HIT.HIT_OTHER_CORE= _NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x04003C0080", + "MSRValue": "0x4003C0080", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1565,7 +1580,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L3_DATA_RD.L3_HIT.NO_SNOOP_NEEDE= D", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x01003C0080", + "MSRValue": "0x1003C0080", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1578,7 +1593,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L3_DATA_RD.L3_HIT.SNOOP_HIT_WITH= _FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x08003C0080", + "MSRValue": "0x8003C0080", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1591,7 +1606,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L3_RFO.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0000010100", + "MSRValue": "0x10100", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1630,7 +1645,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L3_RFO.L3_HIT.HIT_OTHER_CORE_NO_= FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x04003C0100", + "MSRValue": "0x4003C0100", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1643,7 +1658,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L3_RFO.L3_HIT.NO_SNOOP_NEEDED", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x01003C0100", + "MSRValue": "0x1003C0100", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1656,7 +1671,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L3_RFO.L3_HIT.SNOOP_HIT_WITH_FWD= ", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x08003C0100", + "MSRValue": "0x8003C0100", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", diff --git a/tools/perf/pmu-events/arch/x86/skylakex/floating-point.json b/= tools/perf/pmu-events/arch/x86/skylakex/floating-point.json index 503737ed3a83..9e873ab22450 100644 --- a/tools/perf/pmu-events/arch/x86/skylakex/floating-point.json +++ b/tools/perf/pmu-events/arch/x86/skylakex/floating-point.json @@ -1,73 +1,81 @@ [ { - "BriefDescription": "Number of SSE/AVX computational 128-bit packe= d double precision floating-point instructions retired; some instructions w= ill count twice as noted below. Each count represents 2 computation operat= ions, one for each element. Applies to SSE* and AVX* packed double precisi= on floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQ= RT RSQRT14 RCP14 DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count= twice as they perform 2 calculations per element.", + "BriefDescription": "Counts once for most SIMD 128-bit packed comp= utational double precision floating-point instructions retired. Counts twic= e for DPP and FM(N)ADD/SUB instructions retired.", "Counter": "0,1,2,3", "CounterHTOff": "0,1,2,3,4,5,6,7", "EventCode": "0xC7", "EventName": "FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE", + "PublicDescription": "Counts once for most SIMD 128-bit packed com= putational double precision floating-point instructions retired; some instr= uctions will count twice as noted below. Each count represents 2 computati= on operations, one for each element. Applies to packed double precision fl= oating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DP= P FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perf= orm 2 calculations per element. The DAZ and FTZ flags in the MXCSR register= need to be set when using these events.", "SampleAfterValue": "2000003", "UMask": "0x4" }, { - "BriefDescription": "Number of SSE/AVX computational 128-bit packe= d single precision floating-point instructions retired; some instructions w= ill count twice as noted below. Each count represents 4 computation operat= ions, one for each element. Applies to SSE* and AVX* packed single precisi= on floating-point instructions: ADD SUB MUL DIV MIN MAX RCP14 RSQRT14 SQRT = DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they pe= rform 2 calculations per element.", + "BriefDescription": "Counts once for most SIMD 128-bit packed comp= utational single precision floating-point instruction retired. Counts twice= for DPP and FM(N)ADD/SUB instructions retired.", "Counter": "0,1,2,3", "CounterHTOff": "0,1,2,3,4,5,6,7", "EventCode": "0xC7", "EventName": "FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE", + "PublicDescription": "Counts once for most SIMD 128-bit packed com= putational single precision floating-point instructions retired; some instr= uctions will count twice as noted below. Each count represents 4 computati= on operations, one for each element. Applies to packed single precision fl= oating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RS= QRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as= they perform 2 calculations per element. The DAZ and FTZ flags in the MXCS= R register need to be set when using these events.", "SampleAfterValue": "2000003", "UMask": "0x8" }, { - "BriefDescription": "Number of SSE/AVX computational 256-bit packe= d double precision floating-point instructions retired; some instructions w= ill count twice as noted below. Each count represents 4 computation operat= ions, one for each element. Applies to SSE* and AVX* packed double precisi= on floating-point instructions: ADD SUB MUL DIV MIN MAX RCP14 RSQRT14 SQRT = DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they pe= rform 2 calculations per element.", + "BriefDescription": "Counts once for most SIMD 256-bit packed doub= le computational precision floating-point instructions retired. Counts twic= e for DPP and FM(N)ADD/SUB instructions retired.", "Counter": "0,1,2,3", "CounterHTOff": "0,1,2,3,4,5,6,7", "EventCode": "0xC7", "EventName": "FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE", + "PublicDescription": "Counts once for most SIMD 256-bit packed dou= ble computational precision floating-point instructions retired; some instr= uctions will count twice as noted below. Each count represents 4 computati= on operations, one for each element. Applies to packed double precision fl= oating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM= (N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calcul= ations per element. The DAZ and FTZ flags in the MXCSR register need to be = set when using these events.", "SampleAfterValue": "2000003", "UMask": "0x10" }, { - "BriefDescription": "Number of SSE/AVX computational 256-bit packe= d single precision floating-point instructions retired; some instructions w= ill count twice as noted below. Each count represents 8 computation operat= ions, one for each element. Applies to SSE* and AVX* packed single precisi= on floating-point instructions: ADD SUB MUL DIV MIN MAX RCP14 RSQRT14 SQRT = DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they pe= rform 2 calculations per element.", + "BriefDescription": "Counts once for most SIMD 256-bit packed sing= le computational precision floating-point instructions retired. Counts twic= e for DPP and FM(N)ADD/SUB instructions retired.", "Counter": "0,1,2,3", "CounterHTOff": "0,1,2,3,4,5,6,7", "EventCode": "0xC7", "EventName": "FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE", + "PublicDescription": "Counts once for most SIMD 256-bit packed sin= gle computational precision floating-point instructions retired; some instr= uctions will count twice as noted below. Each count represents 8 computati= on operations, one for each element. Applies to packed single precision fl= oating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RS= QRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as= they perform 2 calculations per element. The DAZ and FTZ flags in the MXCS= R register need to be set when using these events.", "SampleAfterValue": "2000003", "UMask": "0x20" }, { - "BriefDescription": "Number of SSE/AVX computational 512-bit packe= d double precision floating-point instructions retired; some instructions w= ill count twice as noted below. Each count represents 8 computation operat= ions, one for each element. Applies to SSE* and AVX* packed double precisi= on floating-point instructions: ADD SUB MUL DIV MIN MAX RCP14 RSQRT14 SQRT = DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they pe= rform 8 calculations per element.", + "BriefDescription": "Counts number of SSE/AVX computational 512-bi= t packed double precision floating-point instructions retired; some instruc= tions will count twice as noted below. Each count represents 8 computation= operations, one for each element. Applies to SSE* and AVX* packed double = precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14= RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform = 2 calculations per element.", "Counter": "0,1,2,3", "CounterHTOff": "0,1,2,3,4,5,6,7", "EventCode": "0xC7", "EventName": "FP_ARITH_INST_RETIRED.512B_PACKED_DOUBLE", + "PublicDescription": "Number of SSE/AVX computational 512-bit pack= ed double precision floating-point instructions retired; some instructions = will count twice as noted below. Each count represents 8 computation opera= tions, one for each element. Applies to SSE* and AVX* packed double precis= ion floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14= FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calc= ulations per element. The DAZ and FTZ flags in the MXCSR register need to b= e set when using these events.", "SampleAfterValue": "2000003", "UMask": "0x40" }, { - "BriefDescription": "Number of SSE/AVX computational 512-bit packe= d single precision floating-point instructions retired; some instructions w= ill count twice as noted below. Each count represents 16 computation opera= tions, one for each element. Applies to SSE* and AVX* packed single precis= ion floating-point instructions: ADD SUB MUL DIV MIN MAX RCP14 RSQRT14 SQRT= DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they p= erform 16 calculations per element.", + "BriefDescription": "Counts number of SSE/AVX computational 512-bi= t packed single precision floating-point instructions retired; some instruc= tions will count twice as noted below. Each count represents 16 computatio= n operations, one for each element. Applies to SSE* and AVX* packed single= precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT1= 4 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform= 2 calculations per element.", "Counter": "0,1,2,3", "CounterHTOff": "0,1,2,3,4,5,6,7", "EventCode": "0xC7", "EventName": "FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE", + "PublicDescription": "Number of SSE/AVX computational 512-bit pack= ed single precision floating-point instructions retired; some instructions = will count twice as noted below. Each count represents 16 computation oper= ations, one for each element. Applies to SSE* and AVX* packed single preci= sion floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP1= 4 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 cal= culations per element. The DAZ and FTZ flags in the MXCSR register need to = be set when using these events.", "SampleAfterValue": "2000003", "UMask": "0x80" }, { - "BriefDescription": "Number of SSE/AVX computational scalar double= precision floating-point instructions retired; some instructions will coun= t twice as noted below. Each count represents 1 computation. Applies to SS= E* and AVX* scalar double precision floating-point instructions: ADD SUB MU= L DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB in= structions count twice as they perform 2 calculations per element.", + "BriefDescription": "Counts once for most SIMD scalar computationa= l double precision floating-point instructions retired. Counts twice for DP= P and FM(N)ADD/SUB instructions retired.", "Counter": "0,1,2,3", "CounterHTOff": "0,1,2,3,4,5,6,7", "EventCode": "0xC7", "EventName": "FP_ARITH_INST_RETIRED.SCALAR_DOUBLE", + "PublicDescription": "Counts once for most SIMD scalar computation= al double precision floating-point instructions retired; some instructions = will count twice as noted below. Each count represents 1 computational ope= ration. Applies to SIMD scalar double precision floating-point instructions= : ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions cou= nt twice as they perform 2 calculations per element. The DAZ and FTZ flags = in the MXCSR register need to be set when using these events.", "SampleAfterValue": "2000003", "UMask": "0x1" }, { - "BriefDescription": "Number of SSE/AVX computational scalar single= precision floating-point instructions retired; some instructions will coun= t twice as noted below. Each count represents 1 computation. Applies to SS= E* and AVX* scalar single precision floating-point instructions: ADD SUB MU= L DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB in= structions count twice as they perform 2 calculations per element.", + "BriefDescription": "Counts once for most SIMD scalar computationa= l single precision floating-point instructions retired. Counts twice for DP= P and FM(N)ADD/SUB instructions retired.", "Counter": "0,1,2,3", "CounterHTOff": "0,1,2,3,4,5,6,7", "EventCode": "0xC7", "EventName": "FP_ARITH_INST_RETIRED.SCALAR_SINGLE", + "PublicDescription": "Counts once for most SIMD scalar computation= al single precision floating-point instructions retired; some instructions = will count twice as noted below. Each count represents 1 computational ope= ration. Applies to SIMD scalar single precision floating-point instructions= : ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instru= ctions count twice as they perform 2 calculations per element. The DAZ and = FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "2000003", "UMask": "0x2" }, diff --git a/tools/perf/pmu-events/arch/x86/skylakex/frontend.json b/tools/= perf/pmu-events/arch/x86/skylakex/frontend.json index 078706a50091..ecce4273ae52 100644 --- a/tools/perf/pmu-events/arch/x86/skylakex/frontend.json +++ b/tools/perf/pmu-events/arch/x86/skylakex/frontend.json @@ -30,7 +30,21 @@ "UMask": "0x2" }, { - "BriefDescription": "Retired Instructions who experienced decode s= tream buffer (DSB - the decoded instruction-cache) miss.", + "BriefDescription": "Retired Instructions who experienced DSB miss= .", + "Counter": "0,1,2,3", + "CounterHTOff": "0,1,2,3", + "EventCode": "0xC6", + "EventName": "FRONTEND_RETIRED.ANY_DSB_MISS", + "MSRIndex": "0x3F7", + "MSRValue": "0x1", + "PEBS": "1", + "PublicDescription": "Counts retired Instructions that experienced= DSB (Decode stream buffer i.e. the decoded instruction-cache) miss.", + "SampleAfterValue": "100007", + "TakenAlone": "1", + "UMask": "0x1" + }, + { + "BriefDescription": "Retired Instructions who experienced a critic= al DSB miss.", "Counter": "0,1,2,3", "CounterHTOff": "0,1,2,3", "EventCode": "0xC6", @@ -38,7 +52,7 @@ "MSRIndex": "0x3F7", "MSRValue": "0x11", "PEBS": "1", - "PublicDescription": "Counts retired Instructions that experienced= DSB (Decode stream buffer i.e. the decoded instruction-cache) miss.", + "PublicDescription": "Number of retired Instructions that experien= ced a critical DSB (Decode stream buffer i.e. the decoded instruction-cache= ) miss. Critical means stalls were exposed to the back-end as a result of t= he DSB miss.", "SampleAfterValue": "100007", "TakenAlone": "1", "UMask": "0x1" diff --git a/tools/perf/pmu-events/arch/x86/skylakex/memory.json b/tools/pe= rf/pmu-events/arch/x86/skylakex/memory.json index 6f29b02fa320..60c286b4fe54 100644 --- a/tools/perf/pmu-events/arch/x86/skylakex/memory.json +++ b/tools/perf/pmu-events/arch/x86/skylakex/memory.json @@ -299,7 +299,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_DATA_RD.L3_MISS.REMOTE_HIT_FORW= ARD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x083FC00491", + "MSRValue": "0x83FC00491", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -312,7 +312,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_DATA_RD.L3_MISS.SNOOP_MISS_OR_N= O_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063FC00491", + "MSRValue": "0x63FC00491", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -325,7 +325,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_DATA_RD.L3_MISS_LOCAL_DRAM.SNOO= P_MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0604000491", + "MSRValue": "0x604000491", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -338,7 +338,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_DATA_RD.L3_MISS_REMOTE_DRAM.SNO= OP_MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063B800491", + "MSRValue": "0x63B800491", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -377,7 +377,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_PF_DATA_RD.L3_MISS.REMOTE_HIT_F= ORWARD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x083FC00490", + "MSRValue": "0x83FC00490", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -390,7 +390,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_PF_DATA_RD.L3_MISS.SNOOP_MISS_O= R_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063FC00490", + "MSRValue": "0x63FC00490", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -403,7 +403,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_PF_DATA_RD.L3_MISS_LOCAL_DRAM.S= NOOP_MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0604000490", + "MSRValue": "0x604000490", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -416,7 +416,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_PF_DATA_RD.L3_MISS_REMOTE_DRAM.= SNOOP_MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063B800490", + "MSRValue": "0x63B800490", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -455,7 +455,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_PF_RFO.L3_MISS.REMOTE_HIT_FORWA= RD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x083FC00120", + "MSRValue": "0x83FC00120", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -468,7 +468,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_PF_RFO.L3_MISS.SNOOP_MISS_OR_NO= _FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063FC00120", + "MSRValue": "0x63FC00120", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -481,7 +481,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_PF_RFO.L3_MISS_LOCAL_DRAM.SNOOP= _MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0604000120", + "MSRValue": "0x604000120", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -494,7 +494,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_PF_RFO.L3_MISS_REMOTE_DRAM.SNOO= P_MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063B800120", + "MSRValue": "0x63B800120", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -533,7 +533,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_RFO.L3_MISS.REMOTE_HIT_FORWARD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x083FC00122", + "MSRValue": "0x83FC00122", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -546,7 +546,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_RFO.L3_MISS.SNOOP_MISS_OR_NO_FW= D", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063FC00122", + "MSRValue": "0x63FC00122", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -559,7 +559,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_RFO.L3_MISS_LOCAL_DRAM.SNOOP_MI= SS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0604000122", + "MSRValue": "0x604000122", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -572,7 +572,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.ALL_RFO.L3_MISS_REMOTE_DRAM.SNOOP_M= ISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063B800122", + "MSRValue": "0x63B800122", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -611,7 +611,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_CODE_RD.L3_MISS.REMOTE_HIT_F= ORWARD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x083FC00004", + "MSRValue": "0x83FC00004", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -624,7 +624,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_CODE_RD.L3_MISS.SNOOP_MISS_O= R_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063FC00004", + "MSRValue": "0x63FC00004", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -637,7 +637,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_CODE_RD.L3_MISS_LOCAL_DRAM.S= NOOP_MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0604000004", + "MSRValue": "0x604000004", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -650,7 +650,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_CODE_RD.L3_MISS_REMOTE_DRAM.= SNOOP_MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063B800004", + "MSRValue": "0x63B800004", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -689,7 +689,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_DATA_RD.L3_MISS.REMOTE_HIT_F= ORWARD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x083FC00001", + "MSRValue": "0x83FC00001", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -702,7 +702,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_DATA_RD.L3_MISS.SNOOP_MISS_O= R_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063FC00001", + "MSRValue": "0x63FC00001", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -715,7 +715,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_DATA_RD.L3_MISS_LOCAL_DRAM.S= NOOP_MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0604000001", + "MSRValue": "0x604000001", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -728,7 +728,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_DATA_RD.L3_MISS_REMOTE_DRAM.= SNOOP_MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063B800001", + "MSRValue": "0x63B800001", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -767,7 +767,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_RFO.L3_MISS.REMOTE_HIT_FORWA= RD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x083FC00002", + "MSRValue": "0x83FC00002", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -780,7 +780,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_RFO.L3_MISS.SNOOP_MISS_OR_NO= _FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063FC00002", + "MSRValue": "0x63FC00002", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -793,7 +793,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_RFO.L3_MISS_LOCAL_DRAM.SNOOP= _MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0604000002", + "MSRValue": "0x604000002", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -806,7 +806,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.DEMAND_RFO.L3_MISS_REMOTE_DRAM.SNOO= P_MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063B800002", + "MSRValue": "0x63B800002", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -845,7 +845,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L1D_AND_SW.L3_MISS.REMOTE_HIT_FO= RWARD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x083FC00400", + "MSRValue": "0x83FC00400", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -858,7 +858,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L1D_AND_SW.L3_MISS.SNOOP_MISS_OR= _NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063FC00400", + "MSRValue": "0x63FC00400", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -871,7 +871,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L1D_AND_SW.L3_MISS_LOCAL_DRAM.SN= OOP_MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0604000400", + "MSRValue": "0x604000400", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -884,7 +884,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L1D_AND_SW.L3_MISS_REMOTE_DRAM.S= NOOP_MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063B800400", + "MSRValue": "0x63B800400", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -923,7 +923,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L2_DATA_RD.L3_MISS.REMOTE_HIT_FO= RWARD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x083FC00010", + "MSRValue": "0x83FC00010", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -936,7 +936,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L2_DATA_RD.L3_MISS.SNOOP_MISS_OR= _NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063FC00010", + "MSRValue": "0x63FC00010", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -949,7 +949,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L2_DATA_RD.L3_MISS_LOCAL_DRAM.SN= OOP_MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0604000010", + "MSRValue": "0x604000010", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -962,7 +962,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L2_DATA_RD.L3_MISS_REMOTE_DRAM.S= NOOP_MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063B800010", + "MSRValue": "0x63B800010", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1001,7 +1001,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L2_RFO.L3_MISS.REMOTE_HIT_FORWAR= D", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x083FC00020", + "MSRValue": "0x83FC00020", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1014,7 +1014,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L2_RFO.L3_MISS.SNOOP_MISS_OR_NO_= FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063FC00020", + "MSRValue": "0x63FC00020", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1027,7 +1027,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L2_RFO.L3_MISS_LOCAL_DRAM.SNOOP_= MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0604000020", + "MSRValue": "0x604000020", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1040,7 +1040,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L2_RFO.L3_MISS_REMOTE_DRAM.SNOOP= _MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063B800020", + "MSRValue": "0x63B800020", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1079,7 +1079,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L3_DATA_RD.L3_MISS.REMOTE_HIT_FO= RWARD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x083FC00080", + "MSRValue": "0x83FC00080", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1092,7 +1092,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L3_DATA_RD.L3_MISS.SNOOP_MISS_OR= _NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063FC00080", + "MSRValue": "0x63FC00080", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1105,7 +1105,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L3_DATA_RD.L3_MISS_LOCAL_DRAM.SN= OOP_MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0604000080", + "MSRValue": "0x604000080", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1118,7 +1118,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L3_DATA_RD.L3_MISS_REMOTE_DRAM.S= NOOP_MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063B800080", + "MSRValue": "0x63B800080", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1157,7 +1157,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L3_RFO.L3_MISS.REMOTE_HIT_FORWAR= D", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x083FC00100", + "MSRValue": "0x83FC00100", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1170,7 +1170,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L3_RFO.L3_MISS.SNOOP_MISS_OR_NO_= FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063FC00100", + "MSRValue": "0x63FC00100", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1183,7 +1183,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L3_RFO.L3_MISS_LOCAL_DRAM.SNOOP_= MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x0604000100", + "MSRValue": "0x604000100", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", @@ -1196,7 +1196,7 @@ "EventCode": "0xB7, 0xBB", "EventName": "OFFCORE_RESPONSE.PF_L3_RFO.L3_MISS_REMOTE_DRAM.SNOOP= _MISS_OR_NO_FWD", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x063B800100", + "MSRValue": "0x63B800100", "Offcore": "1", "PublicDescription": "Offcore response can be programmed only with= a specific pair of event select and counter MSR, and with specific event c= odes and predefine mask bit value in a dedicated MSR to specify attributes = of the offcore transaction.", "SampleAfterValue": "100003", diff --git a/tools/perf/pmu-events/arch/x86/skylakex/pipeline.json b/tools/= perf/pmu-events/arch/x86/skylakex/pipeline.json index ca5748120666..12eabae3e224 100644 --- a/tools/perf/pmu-events/arch/x86/skylakex/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/skylakex/pipeline.json @@ -435,6 +435,17 @@ "PublicDescription": "Counts the number of instructions (EOMs) ret= ired. Counting covers macro-fused instructions individually (that is, incre= ments by two).", "SampleAfterValue": "2000003" }, + { + "BriefDescription": "Number of all retired NOP instructions.", + "Counter": "0,1,2,3", + "CounterHTOff": "0,1,2,3,4,5,6,7", + "Errata": "SKL091, SKL044", + "EventCode": "0xC0", + "EventName": "INST_RETIRED.NOP", + "PEBS": "1", + "SampleAfterValue": "2000003", + "UMask": "0x2" + }, { "BriefDescription": "Precise instruction retired event with HW to = reduce effect of PEBS shadow in IP distribution", "Counter": "1", diff --git a/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json b/too= ls/perf/pmu-events/arch/x86/skylakex/skx-metrics.json index 863c9e103969..b016f7d1ff3d 100644 --- a/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json @@ -1,26 +1,167 @@ [ + { + "BriefDescription": "This category represents fraction of slots wh= ere the processor's Frontend undersupplies its Backend", + "MetricExpr": "IDQ_UOPS_NOT_DELIVERED.CORE / (4 * CPU_CLK_UNHALTED= .THREAD)", + "MetricGroup": "TopdownL1", + "MetricName": "Frontend_Bound", + "PublicDescription": "This category represents fraction of slots w= here the processor's Frontend undersupplies its Backend. Frontend denotes t= he first part of the processor core responsible to fetch operations that ar= e executed later on by the Backend part. Within the Frontend; a branch pred= ictor predicts the next address to fetch; cache-lines are fetched from the = memory subsystem; parsed into instructions; and lastly decoded into micro-o= perations (uops). Ideally the Frontend can issue Machine_Width uops every c= ycle to the Backend. Frontend Bound denotes unutilized issue-slots when the= re is no Backend stall; i.e. bubbles where Frontend delivered no uops while= Backend could have accepted them. For example; stalls due to instruction-c= ache misses would be categorized under Frontend Bound." + }, + { + "BriefDescription": "This category represents fraction of slots wh= ere the processor's Frontend undersupplies its Backend. SMT version; use wh= en SMT is enabled and measuring per logical CPU.", + "MetricExpr": "IDQ_UOPS_NOT_DELIVERED.CORE / (4 * ( ( CPU_CLK_UNHA= LTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHA= LTED.REF_XCLK ) ))", + "MetricGroup": "TopdownL1_SMT", + "MetricName": "Frontend_Bound_SMT", + "PublicDescription": "This category represents fraction of slots w= here the processor's Frontend undersupplies its Backend. Frontend denotes t= he first part of the processor core responsible to fetch operations that ar= e executed later on by the Backend part. Within the Frontend; a branch pred= ictor predicts the next address to fetch; cache-lines are fetched from the = memory subsystem; parsed into instructions; and lastly decoded into micro-o= perations (uops). Ideally the Frontend can issue Machine_Width uops every c= ycle to the Backend. Frontend Bound denotes unutilized issue-slots when the= re is no Backend stall; i.e. bubbles where Frontend delivered no uops while= Backend could have accepted them. For example; stalls due to instruction-c= ache misses would be categorized under Frontend Bound. SMT version; use whe= n SMT is enabled and measuring per logical CPU." + }, + { + "BriefDescription": "This category represents fraction of slots wa= sted due to incorrect speculations", + "MetricExpr": "( UOPS_ISSUED.ANY - UOPS_RETIRED.RETIRE_SLOTS + 4 *= INT_MISC.RECOVERY_CYCLES ) / (4 * CPU_CLK_UNHALTED.THREAD)", + "MetricGroup": "TopdownL1", + "MetricName": "Bad_Speculation", + "PublicDescription": "This category represents fraction of slots w= asted due to incorrect speculations. This include slots used to issue uops = that do not eventually get retired and slots for which the issue-pipeline w= as blocked due to recovery from earlier incorrect speculation. For example;= wasted work due to miss-predicted branches are categorized under Bad Specu= lation category. Incorrect data speculation followed by Memory Ordering Nuk= es is another example." + }, + { + "BriefDescription": "This category represents fraction of slots wa= sted due to incorrect speculations. SMT version; use when SMT is enabled an= d measuring per logical CPU.", + "MetricExpr": "( UOPS_ISSUED.ANY - UOPS_RETIRED.RETIRE_SLOTS + 4 *= ( INT_MISC.RECOVERY_CYCLES_ANY / 2 ) ) / (4 * ( ( CPU_CLK_UNHALTED.THREAD = / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCL= K ) ))", + "MetricGroup": "TopdownL1_SMT", + "MetricName": "Bad_Speculation_SMT", + "PublicDescription": "This category represents fraction of slots w= asted due to incorrect speculations. This include slots used to issue uops = that do not eventually get retired and slots for which the issue-pipeline w= as blocked due to recovery from earlier incorrect speculation. For example;= wasted work due to miss-predicted branches are categorized under Bad Specu= lation category. Incorrect data speculation followed by Memory Ordering Nuk= es is another example. SMT version; use when SMT is enabled and measuring p= er logical CPU." + }, + { + "BriefDescription": "This category represents fraction of slots wh= ere no uops are being delivered due to a lack of required resources for acc= epting new uops in the Backend", + "MetricConstraint": "NO_NMI_WATCHDOG", + "MetricExpr": "1 - (IDQ_UOPS_NOT_DELIVERED.CORE / (4 * CPU_CLK_UNH= ALTED.THREAD)) - ( UOPS_ISSUED.ANY + 4 * INT_MISC.RECOVERY_CYCLES ) / (4 * = CPU_CLK_UNHALTED.THREAD)", + "MetricGroup": "TopdownL1", + "MetricName": "Backend_Bound", + "PublicDescription": "This category represents fraction of slots w= here no uops are being delivered due to a lack of required resources for ac= cepting new uops in the Backend. Backend is the portion of the processor co= re where the out-of-order scheduler dispatches ready uops into their respec= tive execution units; and once completed these uops get retired according t= o program order. For example; stalls due to data-cache misses or stalls due= to the divider unit being overloaded are both categorized under Backend Bo= und. Backend Bound is further divided into two main categories: Memory Boun= d and Core Bound." + }, + { + "BriefDescription": "This category represents fraction of slots wh= ere no uops are being delivered due to a lack of required resources for acc= epting new uops in the Backend. SMT version; use when SMT is enabled and me= asuring per logical CPU.", + "MetricExpr": "1 - (IDQ_UOPS_NOT_DELIVERED.CORE / (4 * ( ( CPU_CLK= _UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK= _UNHALTED.REF_XCLK ) ))) - ( UOPS_ISSUED.ANY + 4 * ( INT_MISC.RECOVERY_CYCL= ES_ANY / 2 ) ) / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNH= ALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))", + "MetricGroup": "TopdownL1_SMT", + "MetricName": "Backend_Bound_SMT", + "PublicDescription": "This category represents fraction of slots w= here no uops are being delivered due to a lack of required resources for ac= cepting new uops in the Backend. Backend is the portion of the processor co= re where the out-of-order scheduler dispatches ready uops into their respec= tive execution units; and once completed these uops get retired according t= o program order. For example; stalls due to data-cache misses or stalls due= to the divider unit being overloaded are both categorized under Backend Bo= und. Backend Bound is further divided into two main categories: Memory Boun= d and Core Bound. SMT version; use when SMT is enabled and measuring per lo= gical CPU." + }, + { + "BriefDescription": "This category represents fraction of slots ut= ilized by useful work i.e. issued uops that eventually get retired", + "MetricExpr": "UOPS_RETIRED.RETIRE_SLOTS / (4 * CPU_CLK_UNHALTED.T= HREAD)", + "MetricGroup": "TopdownL1", + "MetricName": "Retiring", + "PublicDescription": "This category represents fraction of slots u= tilized by useful work i.e. issued uops that eventually get retired. Ideall= y; all pipeline slots would be attributed to the Retiring category. Retiri= ng of 100% would indicate the maximum Pipeline_Width throughput was achieve= d. Maximizing Retiring typically increases the Instructions-per-cycle (see= IPC metric). Note that a high Retiring value does not necessary mean there= is no room for more performance. For example; Heavy-operations or Microco= de Assists are categorized under Retiring. They often indicate suboptimal p= erformance and can often be optimized or avoided. " + }, + { + "BriefDescription": "This category represents fraction of slots ut= ilized by useful work i.e. issued uops that eventually get retired. SMT ver= sion; use when SMT is enabled and measuring per logical CPU.", + "MetricExpr": "UOPS_RETIRED.RETIRE_SLOTS / (4 * ( ( CPU_CLK_UNHALT= ED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALT= ED.REF_XCLK ) ))", + "MetricGroup": "TopdownL1_SMT", + "MetricName": "Retiring_SMT", + "PublicDescription": "This category represents fraction of slots u= tilized by useful work i.e. issued uops that eventually get retired. Ideall= y; all pipeline slots would be attributed to the Retiring category. Retiri= ng of 100% would indicate the maximum Pipeline_Width throughput was achieve= d. Maximizing Retiring typically increases the Instructions-per-cycle (see= IPC metric). Note that a high Retiring value does not necessary mean there= is no room for more performance. For example; Heavy-operations or Microco= de Assists are categorized under Retiring. They often indicate suboptimal p= erformance and can often be optimized or avoided. SMT version; use when SMT= is enabled and measuring per logical CPU." + }, + { + "BriefDescription": "Total pipeline cost of Branch Misprediction r= elated bottlenecks", + "MetricExpr": "100 * ( ((BR_MISP_RETIRED.ALL_BRANCHES / ( BR_MISP_= RETIRED.ALL_BRANCHES + MACHINE_CLEARS.COUNT )) * (( UOPS_ISSUED.ANY - UOPS_= RETIRED.RETIRE_SLOTS + 4 * INT_MISC.RECOVERY_CYCLES ) / (4 * CPU_CLK_UNHALT= ED.THREAD))) + (4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE / (4 * = CPU_CLK_UNHALTED.THREAD)) * ((BR_MISP_RETIRED.ALL_BRANCHES / ( BR_MISP_RETI= RED.ALL_BRANCHES + MACHINE_CLEARS.COUNT )) * INT_MISC.CLEAR_RESTEER_CYCLES = / CPU_CLK_UNHALTED.THREAD) / #(4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DEL= IV.CORE / (4 * CPU_CLK_UNHALTED.THREAD)) )", + "MetricGroup": "Bad;BadSpec;BrMispredicts", + "MetricName": "Mispredictions" + }, + { + "BriefDescription": "Total pipeline cost of Branch Misprediction r= elated bottlenecks", + "MetricExpr": "100 * ( ((BR_MISP_RETIRED.ALL_BRANCHES / ( BR_MISP_= RETIRED.ALL_BRANCHES + MACHINE_CLEARS.COUNT )) * (( UOPS_ISSUED.ANY - UOPS_= RETIRED.RETIRE_SLOTS + 4 * ( INT_MISC.RECOVERY_CYCLES_ANY / 2 ) ) / (4 * ( = ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE = / CPU_CLK_UNHALTED.REF_XCLK ) )))) + (4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_U= OPS_DELIV.CORE / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNH= ALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))) * ((BR_MISP_RETIR= ED.ALL_BRANCHES / ( BR_MISP_RETIRED.ALL_BRANCHES + MACHINE_CLEARS.COUNT )) = * INT_MISC.CLEAR_RESTEER_CYCLES / CPU_CLK_UNHALTED.THREAD) / #(4 * IDQ_UOPS= _NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE / (4 * ( ( CPU_CLK_UNHALTED.THREAD = / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCL= K ) ))) )", + "MetricGroup": "Bad;BadSpec;BrMispredicts_SMT", + "MetricName": "Mispredictions_SMT" + }, + { + "BriefDescription": "Total pipeline cost of (external) Memory Band= width related bottlenecks", + "MetricExpr": "100 * ((( CYCLE_ACTIVITY.STALLS_MEM_ANY + EXE_ACTIV= ITY.BOUND_ON_STORES ) / (CYCLE_ACTIVITY.STALLS_TOTAL + (EXE_ACTIVITY.1_PORT= S_UTIL + (UOPS_RETIRED.RETIRE_SLOTS / (4 * CPU_CLK_UNHALTED.THREAD)) * EXE_= ACTIVITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STORES)) * (1 - (IDQ_UOPS_NO= T_DELIVERED.CORE / (4 * CPU_CLK_UNHALTED.THREAD)) - ( UOPS_ISSUED.ANY + 4 *= INT_MISC.RECOVERY_CYCLES ) / (4 * CPU_CLK_UNHALTED.THREAD))) * ( ( (CYCLE_= ACTIVITY.STALLS_L3_MISS / CPU_CLK_UNHALTED.THREAD + (( CYCLE_ACTIVITY.STALL= S_L1D_MISS - CYCLE_ACTIVITY.STALLS_L2_MISS ) / CPU_CLK_UNHALTED.THREAD) - (= ( (MEM_LOAD_RETIRED.L2_HIT * ( 1 + (MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETI= RED.L1_MISS) )) / ( (MEM_LOAD_RETIRED.L2_HIT * ( 1 + (MEM_LOAD_RETIRED.FB_H= IT / MEM_LOAD_RETIRED.L1_MISS) )) + cpu@L1D_PEND_MISS.FB_FULL\\,cmask\\=3D1= @ ) ) * (( CYCLE_ACTIVITY.STALLS_L1D_MISS - CYCLE_ACTIVITY.STALLS_L2_MISS )= / CPU_CLK_UNHALTED.THREAD))) / #((( CYCLE_ACTIVITY.STALLS_MEM_ANY + EXE_AC= TIVITY.BOUND_ON_STORES ) / (CYCLE_ACTIVITY.STALLS_TOTAL + (EXE_ACTIVITY.1_P= ORTS_UTIL + (UOPS_RETIRED.RETIRE_SLOTS / (4 * CPU_CLK_UNHALTED.THREAD)) * E= XE_ACTIVITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STORES)) * (1 - (IDQ_UOPS= _NOT_DELIVERED.CORE / (4 * CPU_CLK_UNHALTED.THREAD)) - ( UOPS_ISSUED.ANY + = 4 * INT_MISC.RECOVERY_CYCLES ) / (4 * CPU_CLK_UNHALTED.THREAD))) ) * ( (min= ( CPU_CLK_UNHALTED.THREAD , cpu@OFFCORE_REQUESTS_OUTSTANDING.ALL_DATA_RD\\,= cmask\\=3D4@ ) / CPU_CLK_UNHALTED.THREAD) / #(CYCLE_ACTIVITY.STALLS_L3_MISS= / CPU_CLK_UNHALTED.THREAD + (( CYCLE_ACTIVITY.STALLS_L1D_MISS - CYCLE_ACTI= VITY.STALLS_L2_MISS ) / CPU_CLK_UNHALTED.THREAD) - (( (MEM_LOAD_RETIRED.L2_= HIT * ( 1 + (MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) )) / ( (ME= M_LOAD_RETIRED.L2_HIT * ( 1 + (MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L= 1_MISS) )) + cpu@L1D_PEND_MISS.FB_FULL\\,cmask\\=3D1@ ) ) * (( CYCLE_ACTIVI= TY.STALLS_L1D_MISS - CYCLE_ACTIVITY.STALLS_L2_MISS ) / CPU_CLK_UNHALTED.THR= EAD))) ) + ( (( CYCLE_ACTIVITY.STALLS_L2_MISS - CYCLE_ACTIVITY.STALLS_L3_MI= SS ) / CPU_CLK_UNHALTED.THREAD) / #((( CYCLE_ACTIVITY.STALLS_MEM_ANY + EXE_= ACTIVITY.BOUND_ON_STORES ) / (CYCLE_ACTIVITY.STALLS_TOTAL + (EXE_ACTIVITY.1= _PORTS_UTIL + (UOPS_RETIRED.RETIRE_SLOTS / (4 * CPU_CLK_UNHALTED.THREAD)) *= EXE_ACTIVITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STORES)) * (1 - (IDQ_UO= PS_NOT_DELIVERED.CORE / (4 * CPU_CLK_UNHALTED.THREAD)) - ( UOPS_ISSUED.ANY = + 4 * INT_MISC.RECOVERY_CYCLES ) / (4 * CPU_CLK_UNHALTED.THREAD))) ) * ( (O= FFCORE_REQUESTS_BUFFER.SQ_FULL / CPU_CLK_UNHALTED.THREAD) / #(( CYCLE_ACTIV= ITY.STALLS_L2_MISS - CYCLE_ACTIVITY.STALLS_L3_MISS ) / CPU_CLK_UNHALTED.THR= EAD) ) ) + ( (max( ( CYCLE_ACTIVITY.STALLS_MEM_ANY - CYCLE_ACTIVITY.STALLS_= L1D_MISS ) / CPU_CLK_UNHALTED.THREAD , 0 )) / #((( CYCLE_ACTIVITY.STALLS_ME= M_ANY + EXE_ACTIVITY.BOUND_ON_STORES ) / (CYCLE_ACTIVITY.STALLS_TOTAL + (EX= E_ACTIVITY.1_PORTS_UTIL + (UOPS_RETIRED.RETIRE_SLOTS / (4 * CPU_CLK_UNHALTE= D.THREAD)) * EXE_ACTIVITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STORES)) * = (1 - (IDQ_UOPS_NOT_DELIVERED.CORE / (4 * CPU_CLK_UNHALTED.THREAD)) - ( UOPS= _ISSUED.ANY + 4 * INT_MISC.RECOVERY_CYCLES ) / (4 * CPU_CLK_UNHALTED.THREAD= ))) ) * ( ((L1D_PEND_MISS.PENDING / ( MEM_LOAD_RETIRED.L1_MISS + MEM_LOAD_R= ETIRED.FB_HIT )) * cpu@L1D_PEND_MISS.FB_FULL\\,cmask\\=3D1@ / CPU_CLK_UNHAL= TED.THREAD) / #(max( ( CYCLE_ACTIVITY.STALLS_MEM_ANY - CYCLE_ACTIVITY.STALL= S_L1D_MISS ) / CPU_CLK_UNHALTED.THREAD , 0 )) ) ", + "MetricGroup": "Mem;MemoryBW;Offcore", + "MetricName": "Memory_Bandwidth" + }, + { + "BriefDescription": "Total pipeline cost of (external) Memory Band= width related bottlenecks", + "MetricExpr": "100 * ((( CYCLE_ACTIVITY.STALLS_MEM_ANY + EXE_ACTIV= ITY.BOUND_ON_STORES ) / (CYCLE_ACTIVITY.STALLS_TOTAL + (EXE_ACTIVITY.1_PORT= S_UTIL + (UOPS_RETIRED.RETIRE_SLOTS / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 = ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) = ))) * EXE_ACTIVITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STORES)) * (1 - (I= DQ_UOPS_NOT_DELIVERED.CORE / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 += CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))) - ( U= OPS_ISSUED.ANY + 4 * ( INT_MISC.RECOVERY_CYCLES_ANY / 2 ) ) / (4 * ( ( CPU_= CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_= CLK_UNHALTED.REF_XCLK ) )))) * ( ( (CYCLE_ACTIVITY.STALLS_L3_MISS / CPU_CLK= _UNHALTED.THREAD + (( CYCLE_ACTIVITY.STALLS_L1D_MISS - CYCLE_ACTIVITY.STALL= S_L2_MISS ) / CPU_CLK_UNHALTED.THREAD) - (( (MEM_LOAD_RETIRED.L2_HIT * ( 1 = + (MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) )) / ( (MEM_LOAD_RET= IRED.L2_HIT * ( 1 + (MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) ))= + cpu@L1D_PEND_MISS.FB_FULL\\,cmask\\=3D1@ ) ) * (( CYCLE_ACTIVITY.STALLS_= L1D_MISS - CYCLE_ACTIVITY.STALLS_L2_MISS ) / CPU_CLK_UNHALTED.THREAD))) / #= ((( CYCLE_ACTIVITY.STALLS_MEM_ANY + EXE_ACTIVITY.BOUND_ON_STORES ) / (CYCLE= _ACTIVITY.STALLS_TOTAL + (EXE_ACTIVITY.1_PORTS_UTIL + (UOPS_RETIRED.RETIRE_= SLOTS / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE= _THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))) * EXE_ACTIVITY.2_PORTS_UTI= L) + EXE_ACTIVITY.BOUND_ON_STORES)) * (1 - (IDQ_UOPS_NOT_DELIVERED.CORE / (= 4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_A= CTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))) - ( UOPS_ISSUED.ANY + 4 * ( INT_MIS= C.RECOVERY_CYCLES_ANY / 2 ) ) / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( = 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) )))) )= * ( (min( CPU_CLK_UNHALTED.THREAD , cpu@OFFCORE_REQUESTS_OUTSTANDING.ALL_D= ATA_RD\\,cmask\\=3D4@ ) / CPU_CLK_UNHALTED.THREAD) / #(CYCLE_ACTIVITY.STALL= S_L3_MISS / CPU_CLK_UNHALTED.THREAD + (( CYCLE_ACTIVITY.STALLS_L1D_MISS - C= YCLE_ACTIVITY.STALLS_L2_MISS ) / CPU_CLK_UNHALTED.THREAD) - (( (MEM_LOAD_RE= TIRED.L2_HIT * ( 1 + (MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) )= ) / ( (MEM_LOAD_RETIRED.L2_HIT * ( 1 + (MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_= RETIRED.L1_MISS) )) + cpu@L1D_PEND_MISS.FB_FULL\\,cmask\\=3D1@ ) ) * (( CYC= LE_ACTIVITY.STALLS_L1D_MISS - CYCLE_ACTIVITY.STALLS_L2_MISS ) / CPU_CLK_UNH= ALTED.THREAD))) ) + ( (( CYCLE_ACTIVITY.STALLS_L2_MISS - CYCLE_ACTIVITY.STA= LLS_L3_MISS ) / CPU_CLK_UNHALTED.THREAD) / #((( CYCLE_ACTIVITY.STALLS_MEM_A= NY + EXE_ACTIVITY.BOUND_ON_STORES ) / (CYCLE_ACTIVITY.STALLS_TOTAL + (EXE_A= CTIVITY.1_PORTS_UTIL + (UOPS_RETIRED.RETIRE_SLOTS / (4 * ( ( CPU_CLK_UNHALT= ED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALT= ED.REF_XCLK ) ))) * EXE_ACTIVITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STOR= ES)) * (1 - (IDQ_UOPS_NOT_DELIVERED.CORE / (4 * ( ( CPU_CLK_UNHALTED.THREAD= / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XC= LK ) ))) - ( UOPS_ISSUED.ANY + 4 * ( INT_MISC.RECOVERY_CYCLES_ANY / 2 ) ) /= (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD= _ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) )))) ) * ( (( OFFCORE_REQUESTS_BUFFER= .SQ_FULL / 2 ) / ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED= .ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) )) / #(( CYCLE_ACTIVITY.ST= ALLS_L2_MISS - CYCLE_ACTIVITY.STALLS_L3_MISS ) / CPU_CLK_UNHALTED.THREAD) )= ) + ( (max( ( CYCLE_ACTIVITY.STALLS_MEM_ANY - CYCLE_ACTIVITY.STALLS_L1D_MI= SS ) / CPU_CLK_UNHALTED.THREAD , 0 )) / #((( CYCLE_ACTIVITY.STALLS_MEM_ANY = + EXE_ACTIVITY.BOUND_ON_STORES ) / (CYCLE_ACTIVITY.STALLS_TOTAL + (EXE_ACTI= VITY.1_PORTS_UTIL + (UOPS_RETIRED.RETIRE_SLOTS / (4 * ( ( CPU_CLK_UNHALTED.= THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.= REF_XCLK ) ))) * EXE_ACTIVITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STORES)= ) * (1 - (IDQ_UOPS_NOT_DELIVERED.CORE / (4 * ( ( CPU_CLK_UNHALTED.THREAD / = 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK = ) ))) - ( UOPS_ISSUED.ANY + 4 * ( INT_MISC.RECOVERY_CYCLES_ANY / 2 ) ) / (4= * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_AC= TIVE / CPU_CLK_UNHALTED.REF_XCLK ) )))) ) * ( ((L1D_PEND_MISS.PENDING / ( M= EM_LOAD_RETIRED.L1_MISS + MEM_LOAD_RETIRED.FB_HIT )) * cpu@L1D_PEND_MISS.FB= _FULL\\,cmask\\=3D1@ / CPU_CLK_UNHALTED.THREAD) / #(max( ( CYCLE_ACTIVITY.S= TALLS_MEM_ANY - CYCLE_ACTIVITY.STALLS_L1D_MISS ) / CPU_CLK_UNHALTED.THREAD = , 0 )) ) ", + "MetricGroup": "Mem;MemoryBW;Offcore_SMT", + "MetricName": "Memory_Bandwidth_SMT" + }, + { + "BriefDescription": "Total pipeline cost of Memory Latency related= bottlenecks (external memory and off-core caches)", + "MetricExpr": "100 * ((( CYCLE_ACTIVITY.STALLS_MEM_ANY + EXE_ACTIV= ITY.BOUND_ON_STORES ) / (CYCLE_ACTIVITY.STALLS_TOTAL + (EXE_ACTIVITY.1_PORT= S_UTIL + (UOPS_RETIRED.RETIRE_SLOTS / (4 * CPU_CLK_UNHALTED.THREAD)) * EXE_= ACTIVITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STORES)) * (1 - (IDQ_UOPS_NO= T_DELIVERED.CORE / (4 * CPU_CLK_UNHALTED.THREAD)) - ( UOPS_ISSUED.ANY + 4 *= INT_MISC.RECOVERY_CYCLES ) / (4 * CPU_CLK_UNHALTED.THREAD))) * ( ( (CYCLE_= ACTIVITY.STALLS_L3_MISS / CPU_CLK_UNHALTED.THREAD + (( CYCLE_ACTIVITY.STALL= S_L1D_MISS - CYCLE_ACTIVITY.STALLS_L2_MISS ) / CPU_CLK_UNHALTED.THREAD) - (= ( (MEM_LOAD_RETIRED.L2_HIT * ( 1 + (MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETI= RED.L1_MISS) )) / ( (MEM_LOAD_RETIRED.L2_HIT * ( 1 + (MEM_LOAD_RETIRED.FB_H= IT / MEM_LOAD_RETIRED.L1_MISS) )) + cpu@L1D_PEND_MISS.FB_FULL\\,cmask\\=3D1= @ ) ) * (( CYCLE_ACTIVITY.STALLS_L1D_MISS - CYCLE_ACTIVITY.STALLS_L2_MISS )= / CPU_CLK_UNHALTED.THREAD))) / #((( CYCLE_ACTIVITY.STALLS_MEM_ANY + EXE_AC= TIVITY.BOUND_ON_STORES ) / (CYCLE_ACTIVITY.STALLS_TOTAL + (EXE_ACTIVITY.1_P= ORTS_UTIL + (UOPS_RETIRED.RETIRE_SLOTS / (4 * CPU_CLK_UNHALTED.THREAD)) * E= XE_ACTIVITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STORES)) * (1 - (IDQ_UOPS= _NOT_DELIVERED.CORE / (4 * CPU_CLK_UNHALTED.THREAD)) - ( UOPS_ISSUED.ANY + = 4 * INT_MISC.RECOVERY_CYCLES ) / (4 * CPU_CLK_UNHALTED.THREAD))) ) * ( (min= ( CPU_CLK_UNHALTED.THREAD , OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_R= D ) / CPU_CLK_UNHALTED.THREAD - (min( CPU_CLK_UNHALTED.THREAD , cpu@OFFCORE= _REQUESTS_OUTSTANDING.ALL_DATA_RD\\,cmask\\=3D4@ ) / CPU_CLK_UNHALTED.THREA= D)) / #(CYCLE_ACTIVITY.STALLS_L3_MISS / CPU_CLK_UNHALTED.THREAD + (( CYCLE_= ACTIVITY.STALLS_L1D_MISS - CYCLE_ACTIVITY.STALLS_L2_MISS ) / CPU_CLK_UNHALT= ED.THREAD) - (( (MEM_LOAD_RETIRED.L2_HIT * ( 1 + (MEM_LOAD_RETIRED.FB_HIT /= MEM_LOAD_RETIRED.L1_MISS) )) / ( (MEM_LOAD_RETIRED.L2_HIT * ( 1 + (MEM_LOA= D_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) )) + cpu@L1D_PEND_MISS.FB_FULL= \\,cmask\\=3D1@ ) ) * (( CYCLE_ACTIVITY.STALLS_L1D_MISS - CYCLE_ACTIVITY.ST= ALLS_L2_MISS ) / CPU_CLK_UNHALTED.THREAD))) ) + ( (( CYCLE_ACTIVITY.STALLS_= L2_MISS - CYCLE_ACTIVITY.STALLS_L3_MISS ) / CPU_CLK_UNHALTED.THREAD) / #(((= CYCLE_ACTIVITY.STALLS_MEM_ANY + EXE_ACTIVITY.BOUND_ON_STORES ) / (CYCLE_AC= TIVITY.STALLS_TOTAL + (EXE_ACTIVITY.1_PORTS_UTIL + (UOPS_RETIRED.RETIRE_SLO= TS / (4 * CPU_CLK_UNHALTED.THREAD)) * EXE_ACTIVITY.2_PORTS_UTIL) + EXE_ACTI= VITY.BOUND_ON_STORES)) * (1 - (IDQ_UOPS_NOT_DELIVERED.CORE / (4 * CPU_CLK_U= NHALTED.THREAD)) - ( UOPS_ISSUED.ANY + 4 * INT_MISC.RECOVERY_CYCLES ) / (4 = * CPU_CLK_UNHALTED.THREAD))) ) * ( (( (20.5 * ((CPU_CLK_UNHALTED.THREAD / C= PU_CLK_UNHALTED.REF_TSC) * msr@tsc@ / 1000000000 / duration_time)) - (3.5 *= ((CPU_CLK_UNHALTED.THREAD / CPU_CLK_UNHALTED.REF_TSC) * msr@tsc@ / 1000000= 000 / duration_time)) ) * MEM_LOAD_RETIRED.L3_HIT * (1 + (MEM_LOAD_RETIRED.= FB_HIT / MEM_LOAD_RETIRED.L1_MISS) / 2) / CPU_CLK_UNHALTED.THREAD) / #(( CY= CLE_ACTIVITY.STALLS_L2_MISS - CYCLE_ACTIVITY.STALLS_L3_MISS ) / CPU_CLK_UNH= ALTED.THREAD) ) + ( (( (MEM_LOAD_RETIRED.L2_HIT * ( 1 + (MEM_LOAD_RETIRED.F= B_HIT / MEM_LOAD_RETIRED.L1_MISS) )) / ( (MEM_LOAD_RETIRED.L2_HIT * ( 1 + (= MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) )) + cpu@L1D_PEND_MISS.= FB_FULL\\,cmask\\=3D1@ ) ) * (( CYCLE_ACTIVITY.STALLS_L1D_MISS - CYCLE_ACTI= VITY.STALLS_L2_MISS ) / CPU_CLK_UNHALTED.THREAD)) / #((( CYCLE_ACTIVITY.STA= LLS_MEM_ANY + EXE_ACTIVITY.BOUND_ON_STORES ) / (CYCLE_ACTIVITY.STALLS_TOTAL= + (EXE_ACTIVITY.1_PORTS_UTIL + (UOPS_RETIRED.RETIRE_SLOTS / (4 * CPU_CLK_U= NHALTED.THREAD)) * EXE_ACTIVITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STORE= S)) * (1 - (IDQ_UOPS_NOT_DELIVERED.CORE / (4 * CPU_CLK_UNHALTED.THREAD)) - = ( UOPS_ISSUED.ANY + 4 * INT_MISC.RECOVERY_CYCLES ) / (4 * CPU_CLK_UNHALTED.= THREAD))) ) )", + "MetricGroup": "Mem;MemoryLat;Offcore", + "MetricName": "Memory_Latency" + }, + { + "BriefDescription": "Total pipeline cost of Memory Latency related= bottlenecks (external memory and off-core caches)", + "MetricExpr": "100 * ((( CYCLE_ACTIVITY.STALLS_MEM_ANY + EXE_ACTIV= ITY.BOUND_ON_STORES ) / (CYCLE_ACTIVITY.STALLS_TOTAL + (EXE_ACTIVITY.1_PORT= S_UTIL + (UOPS_RETIRED.RETIRE_SLOTS / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 = ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) = ))) * EXE_ACTIVITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STORES)) * (1 - (I= DQ_UOPS_NOT_DELIVERED.CORE / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 += CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))) - ( U= OPS_ISSUED.ANY + 4 * ( INT_MISC.RECOVERY_CYCLES_ANY / 2 ) ) / (4 * ( ( CPU_= CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_= CLK_UNHALTED.REF_XCLK ) )))) * ( ( (CYCLE_ACTIVITY.STALLS_L3_MISS / CPU_CLK= _UNHALTED.THREAD + (( CYCLE_ACTIVITY.STALLS_L1D_MISS - CYCLE_ACTIVITY.STALL= S_L2_MISS ) / CPU_CLK_UNHALTED.THREAD) - (( (MEM_LOAD_RETIRED.L2_HIT * ( 1 = + (MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) )) / ( (MEM_LOAD_RET= IRED.L2_HIT * ( 1 + (MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) ))= + cpu@L1D_PEND_MISS.FB_FULL\\,cmask\\=3D1@ ) ) * (( CYCLE_ACTIVITY.STALLS_= L1D_MISS - CYCLE_ACTIVITY.STALLS_L2_MISS ) / CPU_CLK_UNHALTED.THREAD))) / #= ((( CYCLE_ACTIVITY.STALLS_MEM_ANY + EXE_ACTIVITY.BOUND_ON_STORES ) / (CYCLE= _ACTIVITY.STALLS_TOTAL + (EXE_ACTIVITY.1_PORTS_UTIL + (UOPS_RETIRED.RETIRE_= SLOTS / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE= _THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))) * EXE_ACTIVITY.2_PORTS_UTI= L) + EXE_ACTIVITY.BOUND_ON_STORES)) * (1 - (IDQ_UOPS_NOT_DELIVERED.CORE / (= 4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_A= CTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))) - ( UOPS_ISSUED.ANY + 4 * ( INT_MIS= C.RECOVERY_CYCLES_ANY / 2 ) ) / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( = 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) )))) )= * ( (min( CPU_CLK_UNHALTED.THREAD , OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WI= TH_DATA_RD ) / CPU_CLK_UNHALTED.THREAD - (min( CPU_CLK_UNHALTED.THREAD , cp= u@OFFCORE_REQUESTS_OUTSTANDING.ALL_DATA_RD\\,cmask\\=3D4@ ) / CPU_CLK_UNHAL= TED.THREAD)) / #(CYCLE_ACTIVITY.STALLS_L3_MISS / CPU_CLK_UNHALTED.THREAD + = (( CYCLE_ACTIVITY.STALLS_L1D_MISS - CYCLE_ACTIVITY.STALLS_L2_MISS ) / CPU_C= LK_UNHALTED.THREAD) - (( (MEM_LOAD_RETIRED.L2_HIT * ( 1 + (MEM_LOAD_RETIRED= .FB_HIT / MEM_LOAD_RETIRED.L1_MISS) )) / ( (MEM_LOAD_RETIRED.L2_HIT * ( 1 += (MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) )) + cpu@L1D_PEND_MIS= S.FB_FULL\\,cmask\\=3D1@ ) ) * (( CYCLE_ACTIVITY.STALLS_L1D_MISS - CYCLE_AC= TIVITY.STALLS_L2_MISS ) / CPU_CLK_UNHALTED.THREAD))) ) + ( (( CYCLE_ACTIVIT= Y.STALLS_L2_MISS - CYCLE_ACTIVITY.STALLS_L3_MISS ) / CPU_CLK_UNHALTED.THREA= D) / #((( CYCLE_ACTIVITY.STALLS_MEM_ANY + EXE_ACTIVITY.BOUND_ON_STORES ) / = (CYCLE_ACTIVITY.STALLS_TOTAL + (EXE_ACTIVITY.1_PORTS_UTIL + (UOPS_RETIRED.R= ETIRE_SLOTS / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALT= ED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))) * EXE_ACTIVITY.2_POR= TS_UTIL) + EXE_ACTIVITY.BOUND_ON_STORES)) * (1 - (IDQ_UOPS_NOT_DELIVERED.CO= RE / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_TH= READ_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))) - ( UOPS_ISSUED.ANY + 4 * ( I= NT_MISC.RECOVERY_CYCLES_ANY / 2 ) ) / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 = ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) = )))) ) * ( (( (20.5 * ((CPU_CLK_UNHALTED.THREAD / CPU_CLK_UNHALTED.REF_TSC)= * msr@tsc@ / 1000000000 / duration_time)) - (3.5 * ((CPU_CLK_UNHALTED.THRE= AD / CPU_CLK_UNHALTED.REF_TSC) * msr@tsc@ / 1000000000 / duration_time)) ) = * MEM_LOAD_RETIRED.L3_HIT * (1 + (MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRE= D.L1_MISS) / 2) / CPU_CLK_UNHALTED.THREAD) / #(( CYCLE_ACTIVITY.STALLS_L2_M= ISS - CYCLE_ACTIVITY.STALLS_L3_MISS ) / CPU_CLK_UNHALTED.THREAD) ) + ( (( (= MEM_LOAD_RETIRED.L2_HIT * ( 1 + (MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED= .L1_MISS) )) / ( (MEM_LOAD_RETIRED.L2_HIT * ( 1 + (MEM_LOAD_RETIRED.FB_HIT = / MEM_LOAD_RETIRED.L1_MISS) )) + cpu@L1D_PEND_MISS.FB_FULL\\,cmask\\=3D1@ )= ) * (( CYCLE_ACTIVITY.STALLS_L1D_MISS - CYCLE_ACTIVITY.STALLS_L2_MISS ) / = CPU_CLK_UNHALTED.THREAD)) / #((( CYCLE_ACTIVITY.STALLS_MEM_ANY + EXE_ACTIVI= TY.BOUND_ON_STORES ) / (CYCLE_ACTIVITY.STALLS_TOTAL + (EXE_ACTIVITY.1_PORTS= _UTIL + (UOPS_RETIRED.RETIRE_SLOTS / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 )= * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) )= )) * EXE_ACTIVITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STORES)) * (1 - (ID= Q_UOPS_NOT_DELIVERED.CORE / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + = CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))) - ( UO= PS_ISSUED.ANY + 4 * ( INT_MISC.RECOVERY_CYCLES_ANY / 2 ) ) / (4 * ( ( CPU_C= LK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_C= LK_UNHALTED.REF_XCLK ) )))) ) )", + "MetricGroup": "Mem;MemoryLat;Offcore_SMT", + "MetricName": "Memory_Latency_SMT" + }, + { + "BriefDescription": "Total pipeline cost of Memory Address Transla= tion related bottlenecks (data-side TLBs)", + "MetricExpr": "100 * ((( CYCLE_ACTIVITY.STALLS_MEM_ANY + EXE_ACTIV= ITY.BOUND_ON_STORES ) / (CYCLE_ACTIVITY.STALLS_TOTAL + (EXE_ACTIVITY.1_PORT= S_UTIL + (UOPS_RETIRED.RETIRE_SLOTS / (4 * CPU_CLK_UNHALTED.THREAD)) * EXE_= ACTIVITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STORES)) * (1 - (IDQ_UOPS_NO= T_DELIVERED.CORE / (4 * CPU_CLK_UNHALTED.THREAD)) - ( UOPS_ISSUED.ANY + 4 *= INT_MISC.RECOVERY_CYCLES ) / (4 * CPU_CLK_UNHALTED.THREAD))) * ( ( (max( (= CYCLE_ACTIVITY.STALLS_MEM_ANY - CYCLE_ACTIVITY.STALLS_L1D_MISS ) / CPU_CLK= _UNHALTED.THREAD , 0 )) / ((( CYCLE_ACTIVITY.STALLS_MEM_ANY + EXE_ACTIVITY.= BOUND_ON_STORES ) / (CYCLE_ACTIVITY.STALLS_TOTAL + (EXE_ACTIVITY.1_PORTS_UT= IL + (UOPS_RETIRED.RETIRE_SLOTS / (4 * CPU_CLK_UNHALTED.THREAD)) * EXE_ACTI= VITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STORES)) * (1 - (IDQ_UOPS_NOT_DE= LIVERED.CORE / (4 * CPU_CLK_UNHALTED.THREAD)) - ( UOPS_ISSUED.ANY + 4 * INT= _MISC.RECOVERY_CYCLES ) / (4 * CPU_CLK_UNHALTED.THREAD))) ) * ( (min( 9 * c= pu@DTLB_LOAD_MISSES.STLB_HIT\\,cmask\\=3D1@ + DTLB_LOAD_MISSES.WALK_ACTIVE = , max( CYCLE_ACTIVITY.CYCLES_MEM_ANY - CYCLE_ACTIVITY.CYCLES_L1D_MISS , 0 )= ) / CPU_CLK_UNHALTED.THREAD) / (max( ( CYCLE_ACTIVITY.STALLS_MEM_ANY - CYC= LE_ACTIVITY.STALLS_L1D_MISS ) / CPU_CLK_UNHALTED.THREAD , 0 )) ) + ( (EXE_A= CTIVITY.BOUND_ON_STORES / CPU_CLK_UNHALTED.THREAD) / #((( CYCLE_ACTIVITY.ST= ALLS_MEM_ANY + EXE_ACTIVITY.BOUND_ON_STORES ) / (CYCLE_ACTIVITY.STALLS_TOTA= L + (EXE_ACTIVITY.1_PORTS_UTIL + (UOPS_RETIRED.RETIRE_SLOTS / (4 * CPU_CLK_= UNHALTED.THREAD)) * EXE_ACTIVITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STOR= ES)) * (1 - (IDQ_UOPS_NOT_DELIVERED.CORE / (4 * CPU_CLK_UNHALTED.THREAD)) -= ( UOPS_ISSUED.ANY + 4 * INT_MISC.RECOVERY_CYCLES ) / (4 * CPU_CLK_UNHALTED= .THREAD))) ) * ( (( 9 * cpu@DTLB_STORE_MISSES.STLB_HIT\\,cmask\\=3D1@ + DTL= B_STORE_MISSES.WALK_ACTIVE ) / CPU_CLK_UNHALTED.THREAD) / #(EXE_ACTIVITY.BO= UND_ON_STORES / CPU_CLK_UNHALTED.THREAD) ) ) ", + "MetricGroup": "Mem;MemoryTLB", + "MetricName": "Memory_Data_TLBs" + }, + { + "BriefDescription": "Total pipeline cost of Memory Address Transla= tion related bottlenecks (data-side TLBs)", + "MetricExpr": "100 * ((( CYCLE_ACTIVITY.STALLS_MEM_ANY + EXE_ACTIV= ITY.BOUND_ON_STORES ) / (CYCLE_ACTIVITY.STALLS_TOTAL + (EXE_ACTIVITY.1_PORT= S_UTIL + (UOPS_RETIRED.RETIRE_SLOTS / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 = ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) = ))) * EXE_ACTIVITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STORES)) * (1 - (I= DQ_UOPS_NOT_DELIVERED.CORE / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 += CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))) - ( U= OPS_ISSUED.ANY + 4 * ( INT_MISC.RECOVERY_CYCLES_ANY / 2 ) ) / (4 * ( ( CPU_= CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_= CLK_UNHALTED.REF_XCLK ) )))) * ( ( (max( ( CYCLE_ACTIVITY.STALLS_MEM_ANY - = CYCLE_ACTIVITY.STALLS_L1D_MISS ) / CPU_CLK_UNHALTED.THREAD , 0 )) / ((( CYC= LE_ACTIVITY.STALLS_MEM_ANY + EXE_ACTIVITY.BOUND_ON_STORES ) / (CYCLE_ACTIVI= TY.STALLS_TOTAL + (EXE_ACTIVITY.1_PORTS_UTIL + (UOPS_RETIRED.RETIRE_SLOTS /= (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD= _ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))) * EXE_ACTIVITY.2_PORTS_UTIL) + EX= E_ACTIVITY.BOUND_ON_STORES)) * (1 - (IDQ_UOPS_NOT_DELIVERED.CORE / (4 * ( (= CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE /= CPU_CLK_UNHALTED.REF_XCLK ) ))) - ( UOPS_ISSUED.ANY + 4 * ( INT_MISC.RECOV= ERY_CYCLES_ANY / 2 ) ) / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU= _CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) )))) ) * ( (m= in( 9 * cpu@DTLB_LOAD_MISSES.STLB_HIT\\,cmask\\=3D1@ + DTLB_LOAD_MISSES.WAL= K_ACTIVE , max( CYCLE_ACTIVITY.CYCLES_MEM_ANY - CYCLE_ACTIVITY.CYCLES_L1D_M= ISS , 0 ) ) / CPU_CLK_UNHALTED.THREAD) / (max( ( CYCLE_ACTIVITY.STALLS_MEM_= ANY - CYCLE_ACTIVITY.STALLS_L1D_MISS ) / CPU_CLK_UNHALTED.THREAD , 0 )) ) += ( (EXE_ACTIVITY.BOUND_ON_STORES / CPU_CLK_UNHALTED.THREAD) / #((( CYCLE_AC= TIVITY.STALLS_MEM_ANY + EXE_ACTIVITY.BOUND_ON_STORES ) / (CYCLE_ACTIVITY.ST= ALLS_TOTAL + (EXE_ACTIVITY.1_PORTS_UTIL + (UOPS_RETIRED.RETIRE_SLOTS / (4 *= ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTI= VE / CPU_CLK_UNHALTED.REF_XCLK ) ))) * EXE_ACTIVITY.2_PORTS_UTIL) + EXE_ACT= IVITY.BOUND_ON_STORES)) * (1 - (IDQ_UOPS_NOT_DELIVERED.CORE / (4 * ( ( CPU_= CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_= CLK_UNHALTED.REF_XCLK ) ))) - ( UOPS_ISSUED.ANY + 4 * ( INT_MISC.RECOVERY_C= YCLES_ANY / 2 ) ) / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_= UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) )))) ) * ( (( 9 * = cpu@DTLB_STORE_MISSES.STLB_HIT\\,cmask\\=3D1@ + DTLB_STORE_MISSES.WALK_ACTI= VE ) / ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREA= D_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) )) / #(EXE_ACTIVITY.BOUND_ON_STORES = / CPU_CLK_UNHALTED.THREAD) ) ) ", + "MetricGroup": "Mem;MemoryTLB;_SMT", + "MetricName": "Memory_Data_TLBs_SMT" + }, + { + "BriefDescription": "Total pipeline cost of branch related instruc= tions (used for program control-flow including function calls)", + "MetricExpr": "100 * (( BR_INST_RETIRED.CONDITIONAL + 3 * BR_INST_= RETIRED.NEAR_CALL + (BR_INST_RETIRED.NEAR_TAKEN - ( BR_INST_RETIRED.CONDITI= ONAL - BR_INST_RETIRED.NOT_TAKEN ) - 2 * BR_INST_RETIRED.NEAR_CALL) ) / (4 = * CPU_CLK_UNHALTED.THREAD))", + "MetricGroup": "Ret", + "MetricName": "Branching_Overhead" + }, + { + "BriefDescription": "Total pipeline cost of branch related instruc= tions (used for program control-flow including function calls)", + "MetricExpr": "100 * (( BR_INST_RETIRED.CONDITIONAL + 3 * BR_INST_= RETIRED.NEAR_CALL + (BR_INST_RETIRED.NEAR_TAKEN - ( BR_INST_RETIRED.CONDITI= ONAL - BR_INST_RETIRED.NOT_TAKEN ) - 2 * BR_INST_RETIRED.NEAR_CALL) ) / (4 = * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACT= IVE / CPU_CLK_UNHALTED.REF_XCLK ) )))", + "MetricGroup": "Ret_SMT", + "MetricName": "Branching_Overhead_SMT" + }, + { + "BriefDescription": "Total pipeline cost of instruction fetch rela= ted bottlenecks by large code footprint programs (i-side cache; TLB and BTB= misses)", + "MetricExpr": "100 * (4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DEL= IV.CORE / (4 * CPU_CLK_UNHALTED.THREAD)) * ( (ICACHE_64B.IFTAG_STALL / CPU_= CLK_UNHALTED.THREAD) + (( ICACHE_16B.IFDATA_STALL + 2 * cpu@ICACHE_16B.IFDA= TA_STALL\\,cmask\\=3D1\\,edge@ ) / CPU_CLK_UNHALTED.THREAD) + (9 * BACLEARS= .ANY / CPU_CLK_UNHALTED.THREAD) ) / #(4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_U= OPS_DELIV.CORE / (4 * CPU_CLK_UNHALTED.THREAD))", + "MetricGroup": "BigFoot;Fed;Frontend;IcMiss;MemoryTLB", + "MetricName": "Big_Code" + }, + { + "BriefDescription": "Total pipeline cost of instruction fetch rela= ted bottlenecks by large code footprint programs (i-side cache; TLB and BTB= misses)", + "MetricExpr": "100 * (4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DEL= IV.CORE / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.O= NE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))) * ( (ICACHE_64B.IFTAG_ST= ALL / CPU_CLK_UNHALTED.THREAD) + (( ICACHE_16B.IFDATA_STALL + 2 * cpu@ICACH= E_16B.IFDATA_STALL\\,cmask\\=3D1\\,edge@ ) / CPU_CLK_UNHALTED.THREAD) + (9 = * BACLEARS.ANY / CPU_CLK_UNHALTED.THREAD) ) / #(4 * IDQ_UOPS_NOT_DELIVERED.= CYCLES_0_UOPS_DELIV.CORE / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + C= PU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) )))", + "MetricGroup": "BigFoot;Fed;Frontend;IcMiss;MemoryTLB_SMT", + "MetricName": "Big_Code_SMT" + }, + { + "BriefDescription": "Total pipeline cost of instruction fetch band= width related bottlenecks", + "MetricExpr": "100 * ( (IDQ_UOPS_NOT_DELIVERED.CORE / (4 * CPU_CLK= _UNHALTED.THREAD)) - (4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE /= (4 * CPU_CLK_UNHALTED.THREAD)) * ((BR_MISP_RETIRED.ALL_BRANCHES / ( BR_MIS= P_RETIRED.ALL_BRANCHES + MACHINE_CLEARS.COUNT )) * INT_MISC.CLEAR_RESTEER_C= YCLES / CPU_CLK_UNHALTED.THREAD) / #(4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UO= PS_DELIV.CORE / (4 * CPU_CLK_UNHALTED.THREAD)) ) - (100 * (4 * IDQ_UOPS_NOT= _DELIVERED.CYCLES_0_UOPS_DELIV.CORE / (4 * CPU_CLK_UNHALTED.THREAD)) * ( (I= CACHE_64B.IFTAG_STALL / CPU_CLK_UNHALTED.THREAD) + (( ICACHE_16B.IFDATA_STA= LL + 2 * cpu@ICACHE_16B.IFDATA_STALL\\,cmask\\=3D1\\,edge@ ) / CPU_CLK_UNHA= LTED.THREAD) + (9 * BACLEARS.ANY / CPU_CLK_UNHALTED.THREAD) ) / #(4 * IDQ_U= OPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE / (4 * CPU_CLK_UNHALTED.THREAD))= )", + "MetricGroup": "Fed;FetchBW;Frontend", + "MetricName": "Instruction_Fetch_BW" + }, + { + "BriefDescription": "Total pipeline cost of instruction fetch band= width related bottlenecks", + "MetricExpr": "100 * ( (IDQ_UOPS_NOT_DELIVERED.CORE / (4 * ( ( CPU= _CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU= _CLK_UNHALTED.REF_XCLK ) ))) - (4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DE= LIV.CORE / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.= ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))) * ((BR_MISP_RETIRED.ALL= _BRANCHES / ( BR_MISP_RETIRED.ALL_BRANCHES + MACHINE_CLEARS.COUNT )) * INT_= MISC.CLEAR_RESTEER_CYCLES / CPU_CLK_UNHALTED.THREAD) / #(4 * IDQ_UOPS_NOT_D= ELIVERED.CYCLES_0_UOPS_DELIV.CORE / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) = * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))= ) ) - (100 * (4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE / (4 * ( = ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE = / CPU_CLK_UNHALTED.REF_XCLK ) ))) * ( (ICACHE_64B.IFTAG_STALL / CPU_CLK_UNH= ALTED.THREAD) + (( ICACHE_16B.IFDATA_STALL + 2 * cpu@ICACHE_16B.IFDATA_STAL= L\\,cmask\\=3D1\\,edge@ ) / CPU_CLK_UNHALTED.THREAD) + (9 * BACLEARS.ANY / = CPU_CLK_UNHALTED.THREAD) ) / #(4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DEL= IV.CORE / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.O= NE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))))", + "MetricGroup": "Fed;FetchBW;Frontend_SMT", + "MetricName": "Instruction_Fetch_BW_SMT" + }, { "BriefDescription": "Instructions Per Cycle (per Logical Processor= )", "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD", - "MetricGroup": "Summary", + "MetricGroup": "Ret;Summary", "MetricName": "IPC" }, { "BriefDescription": "Uops Per Instruction", "MetricExpr": "UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY", - "MetricGroup": "Pipeline;Retire", + "MetricGroup": "Pipeline;Ret;Retire", "MetricName": "UPI" }, { "BriefDescription": "Instruction per taken branch", - "MetricExpr": "INST_RETIRED.ANY / BR_INST_RETIRED.NEAR_TAKEN", - "MetricGroup": "Branches;FetchBW;PGO", - "MetricName": "IpTB" + "MetricExpr": "UOPS_RETIRED.RETIRE_SLOTS / BR_INST_RETIRED.NEAR_TA= KEN", + "MetricGroup": "Branches;Fed;FetchBW", + "MetricName": "UpTB" }, { "BriefDescription": "Cycles Per Instruction (per Logical Processor= )", "MetricExpr": "1 / (INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD)", - "MetricGroup": "Pipeline", + "MetricGroup": "Pipeline;Mem", "MetricName": "CPI" }, { @@ -30,39 +171,84 @@ "MetricName": "CLKS" }, { - "BriefDescription": "Instructions Per Cycle (per physical core)", + "BriefDescription": "Total issue-pipeline slots (per-Physical Core= till ICL; per-Logical Processor ICL onward)", + "MetricExpr": "4 * CPU_CLK_UNHALTED.THREAD", + "MetricGroup": "TmaL1", + "MetricName": "SLOTS" + }, + { + "BriefDescription": "Total issue-pipeline slots (per-Physical Core= till ICL; per-Logical Processor ICL onward)", + "MetricExpr": "4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_C= LK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) )", + "MetricGroup": "TmaL1_SMT", + "MetricName": "SLOTS_SMT" + }, + { + "BriefDescription": "The ratio of Executed- by Issued-Uops", + "MetricExpr": "UOPS_EXECUTED.THREAD / UOPS_ISSUED.ANY", + "MetricGroup": "Cor;Pipeline", + "MetricName": "Execute_per_Issue", + "PublicDescription": "The ratio of Executed- by Issued-Uops. Ratio= > 1 suggests high rate of uop micro-fusions. Ratio < 1 suggest high rate o= f \"execute\" at rename stage." + }, + { + "BriefDescription": "Instructions Per Cycle across hyper-threads (= per physical core)", "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD", - "MetricGroup": "SMT;TmaL1", + "MetricGroup": "Ret;SMT;TmaL1", "MetricName": "CoreIPC" }, { - "BriefDescription": "Instructions Per Cycle (per physical core)", + "BriefDescription": "Instructions Per Cycle across hyper-threads (= per physical core)", "MetricExpr": "INST_RETIRED.ANY / ( ( CPU_CLK_UNHALTED.THREAD / 2 = ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) = )", - "MetricGroup": "SMT;TmaL1", + "MetricGroup": "Ret;SMT;TmaL1_SMT", "MetricName": "CoreIPC_SMT" }, { "BriefDescription": "Floating Point Operations Per Cycle", "MetricExpr": "( 1 * ( FP_ARITH_INST_RETIRED.SCALAR_SINGLE + FP_AR= ITH_INST_RETIRED.SCALAR_DOUBLE ) + 2 * FP_ARITH_INST_RETIRED.128B_PACKED_DO= UBLE + 4 * ( FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE + FP_ARITH_INST_RETIR= ED.256B_PACKED_DOUBLE ) + 8 * ( FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE + = FP_ARITH_INST_RETIRED.512B_PACKED_DOUBLE ) + 16 * FP_ARITH_INST_RETIRED.512= B_PACKED_SINGLE ) / CPU_CLK_UNHALTED.THREAD", - "MetricGroup": "Flops", + "MetricGroup": "Ret;Flops", "MetricName": "FLOPc" }, { "BriefDescription": "Floating Point Operations Per Cycle", "MetricExpr": "( 1 * ( FP_ARITH_INST_RETIRED.SCALAR_SINGLE + FP_AR= ITH_INST_RETIRED.SCALAR_DOUBLE ) + 2 * FP_ARITH_INST_RETIRED.128B_PACKED_DO= UBLE + 4 * ( FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE + FP_ARITH_INST_RETIR= ED.256B_PACKED_DOUBLE ) + 8 * ( FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE + = FP_ARITH_INST_RETIRED.512B_PACKED_DOUBLE ) + 16 * FP_ARITH_INST_RETIRED.512= B_PACKED_SINGLE ) / ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHAL= TED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) )", - "MetricGroup": "Flops_SMT", + "MetricGroup": "Ret;Flops_SMT", "MetricName": "FLOPc_SMT" }, + { + "BriefDescription": "Actual per-core usage of the Floating Point e= xecution units (regardless of the vector width)", + "MetricExpr": "( (FP_ARITH_INST_RETIRED.SCALAR_SINGLE + FP_ARITH_I= NST_RETIRED.SCALAR_DOUBLE) + (FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE + FP= _ARITH_INST_RETIRED.128B_PACKED_SINGLE + FP_ARITH_INST_RETIRED.256B_PACKED_= DOUBLE + FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE + FP_ARITH_INST_RETIRED.5= 12B_PACKED_DOUBLE + FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE) ) / ( 2 * CPU= _CLK_UNHALTED.THREAD )", + "MetricGroup": "Cor;Flops;HPC", + "MetricName": "FP_Arith_Utilization", + "PublicDescription": "Actual per-core usage of the Floating Point = execution units (regardless of the vector width). Values > 1 are possible d= ue to Fused-Multiply Add (FMA) counting." + }, + { + "BriefDescription": "Actual per-core usage of the Floating Point e= xecution units (regardless of the vector width). SMT version; use when SMT = is enabled and measuring per logical CPU.", + "MetricExpr": "( (FP_ARITH_INST_RETIRED.SCALAR_SINGLE + FP_ARITH_I= NST_RETIRED.SCALAR_DOUBLE) + (FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE + FP= _ARITH_INST_RETIRED.128B_PACKED_SINGLE + FP_ARITH_INST_RETIRED.256B_PACKED_= DOUBLE + FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE + FP_ARITH_INST_RETIRED.5= 12B_PACKED_DOUBLE + FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE) ) / ( 2 * ( (= CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE /= CPU_CLK_UNHALTED.REF_XCLK ) ) )", + "MetricGroup": "Cor;Flops;HPC_SMT", + "MetricName": "FP_Arith_Utilization_SMT", + "PublicDescription": "Actual per-core usage of the Floating Point = execution units (regardless of the vector width). Values > 1 are possible d= ue to Fused-Multiply Add (FMA) counting. SMT version; use when SMT is enabl= ed and measuring per logical CPU." + }, { "BriefDescription": "Instruction-Level-Parallelism (average number= of uops executed when there is at least 1 uop executed)", "MetricExpr": "UOPS_EXECUTED.THREAD / (( UOPS_EXECUTED.CORE_CYCLES= _GE_1 / 2 ) if #SMT_on else UOPS_EXECUTED.CORE_CYCLES_GE_1)", - "MetricGroup": "Pipeline;PortsUtil", + "MetricGroup": "Backend;Cor;Pipeline;PortsUtil", "MetricName": "ILP" }, + { + "BriefDescription": "Branch Misprediction Cost: Fraction of TMA sl= ots wasted per non-speculative branch misprediction (retired JEClear)", + "MetricExpr": " ( ((BR_MISP_RETIRED.ALL_BRANCHES / ( BR_MISP_RETIR= ED.ALL_BRANCHES + MACHINE_CLEARS.COUNT )) * (( UOPS_ISSUED.ANY - UOPS_RETIR= ED.RETIRE_SLOTS + 4 * INT_MISC.RECOVERY_CYCLES ) / (4 * CPU_CLK_UNHALTED.TH= READ))) + (4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE / (4 * CPU_C= LK_UNHALTED.THREAD)) * ((BR_MISP_RETIRED.ALL_BRANCHES / ( BR_MISP_RETIRED.A= LL_BRANCHES + MACHINE_CLEARS.COUNT )) * INT_MISC.CLEAR_RESTEER_CYCLES / CPU= _CLK_UNHALTED.THREAD) / #(4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CO= RE / (4 * CPU_CLK_UNHALTED.THREAD)) ) * (4 * CPU_CLK_UNHALTED.THREAD) / BR_= MISP_RETIRED.ALL_BRANCHES", + "MetricGroup": "Bad;BrMispredicts", + "MetricName": "Branch_Misprediction_Cost" + }, + { + "BriefDescription": "Branch Misprediction Cost: Fraction of TMA sl= ots wasted per non-speculative branch misprediction (retired JEClear)", + "MetricExpr": " ( ((BR_MISP_RETIRED.ALL_BRANCHES / ( BR_MISP_RETIR= ED.ALL_BRANCHES + MACHINE_CLEARS.COUNT )) * (( UOPS_ISSUED.ANY - UOPS_RETIR= ED.RETIRE_SLOTS + 4 * ( INT_MISC.RECOVERY_CYCLES_ANY / 2 ) ) / (4 * ( ( CPU= _CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU= _CLK_UNHALTED.REF_XCLK ) )))) + (4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_D= ELIV.CORE / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED= .ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))) * ((BR_MISP_RETIRED.AL= L_BRANCHES / ( BR_MISP_RETIRED.ALL_BRANCHES + MACHINE_CLEARS.COUNT )) * INT= _MISC.CLEAR_RESTEER_CYCLES / CPU_CLK_UNHALTED.THREAD) / #(4 * IDQ_UOPS_NOT_= DELIVERED.CYCLES_0_UOPS_DELIV.CORE / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 )= * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) )= )) ) * (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_= THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) )) / BR_MISP_RETIRED.ALL_BRANCH= ES", + "MetricGroup": "Bad;BrMispredicts_SMT", + "MetricName": "Branch_Misprediction_Cost_SMT" + }, { "BriefDescription": "Number of Instructions per non-speculative Br= anch Misprediction (JEClear)", "MetricExpr": "INST_RETIRED.ANY / BR_MISP_RETIRED.ALL_BRANCHES", - "MetricGroup": "BrMispredicts", + "MetricGroup": "Bad;BadSpec;BrMispredicts", "MetricName": "IpMispredict" }, { @@ -86,122 +272,249 @@ { "BriefDescription": "Instructions per Branch (lower number means h= igher occurrence rate)", "MetricExpr": "INST_RETIRED.ANY / BR_INST_RETIRED.ALL_BRANCHES", - "MetricGroup": "Branches;InsType", + "MetricGroup": "Branches;Fed;InsType", "MetricName": "IpBranch" }, { "BriefDescription": "Instructions per (near) call (lower number me= ans higher occurrence rate)", "MetricExpr": "INST_RETIRED.ANY / BR_INST_RETIRED.NEAR_CALL", - "MetricGroup": "Branches", + "MetricGroup": "Branches;Fed;PGO", "MetricName": "IpCall" }, + { + "BriefDescription": "Instruction per taken branch", + "MetricExpr": "INST_RETIRED.ANY / BR_INST_RETIRED.NEAR_TAKEN", + "MetricGroup": "Branches;Fed;FetchBW;Frontend;PGO", + "MetricName": "IpTB" + }, { "BriefDescription": "Branch instructions per taken branch. ", "MetricExpr": "BR_INST_RETIRED.ALL_BRANCHES / BR_INST_RETIRED.NEAR= _TAKEN", - "MetricGroup": "Branches;PGO", + "MetricGroup": "Branches;Fed;PGO", "MetricName": "BpTkBranch" }, { "BriefDescription": "Instructions per Floating Point (FP) Operatio= n (lower number means higher occurrence rate)", "MetricExpr": "INST_RETIRED.ANY / ( 1 * ( FP_ARITH_INST_RETIRED.SC= ALAR_SINGLE + FP_ARITH_INST_RETIRED.SCALAR_DOUBLE ) + 2 * FP_ARITH_INST_RET= IRED.128B_PACKED_DOUBLE + 4 * ( FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE + = FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE ) + 8 * ( FP_ARITH_INST_RETIRED.25= 6B_PACKED_SINGLE + FP_ARITH_INST_RETIRED.512B_PACKED_DOUBLE ) + 16 * FP_ARI= TH_INST_RETIRED.512B_PACKED_SINGLE )", - "MetricGroup": "Flops;FpArith;InsType", + "MetricGroup": "Flops;InsType", "MetricName": "IpFLOP" }, + { + "BriefDescription": "Instructions per FP Arithmetic instruction (l= ower number means higher occurrence rate)", + "MetricExpr": "INST_RETIRED.ANY / ( (FP_ARITH_INST_RETIRED.SCALAR_= SINGLE + FP_ARITH_INST_RETIRED.SCALAR_DOUBLE) + (FP_ARITH_INST_RETIRED.128B= _PACKED_DOUBLE + FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE + FP_ARITH_INST_R= ETIRED.256B_PACKED_DOUBLE + FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE + FP_A= RITH_INST_RETIRED.512B_PACKED_DOUBLE + FP_ARITH_INST_RETIRED.512B_PACKED_SI= NGLE) )", + "MetricGroup": "Flops;InsType", + "MetricName": "IpArith", + "PublicDescription": "Instructions per FP Arithmetic instruction (= lower number means higher occurrence rate). May undercount due to FMA doubl= e counting. Approximated prior to BDW." + }, + { + "BriefDescription": "Instructions per FP Arithmetic Scalar Single-= Precision instruction (lower number means higher occurrence rate)", + "MetricExpr": "INST_RETIRED.ANY / FP_ARITH_INST_RETIRED.SCALAR_SIN= GLE", + "MetricGroup": "Flops;FpScalar;InsType", + "MetricName": "IpArith_Scalar_SP", + "PublicDescription": "Instructions per FP Arithmetic Scalar Single= -Precision instruction (lower number means higher occurrence rate). May und= ercount due to FMA double counting." + }, + { + "BriefDescription": "Instructions per FP Arithmetic Scalar Double-= Precision instruction (lower number means higher occurrence rate)", + "MetricExpr": "INST_RETIRED.ANY / FP_ARITH_INST_RETIRED.SCALAR_DOU= BLE", + "MetricGroup": "Flops;FpScalar;InsType", + "MetricName": "IpArith_Scalar_DP", + "PublicDescription": "Instructions per FP Arithmetic Scalar Double= -Precision instruction (lower number means higher occurrence rate). May und= ercount due to FMA double counting." + }, + { + "BriefDescription": "Instructions per FP Arithmetic AVX/SSE 128-bi= t instruction (lower number means higher occurrence rate)", + "MetricExpr": "INST_RETIRED.ANY / ( FP_ARITH_INST_RETIRED.128B_PAC= KED_DOUBLE + FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE )", + "MetricGroup": "Flops;FpVector;InsType", + "MetricName": "IpArith_AVX128", + "PublicDescription": "Instructions per FP Arithmetic AVX/SSE 128-b= it instruction (lower number means higher occurrence rate). May undercount = due to FMA double counting." + }, + { + "BriefDescription": "Instructions per FP Arithmetic AVX* 256-bit i= nstruction (lower number means higher occurrence rate)", + "MetricExpr": "INST_RETIRED.ANY / ( FP_ARITH_INST_RETIRED.256B_PAC= KED_DOUBLE + FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE )", + "MetricGroup": "Flops;FpVector;InsType", + "MetricName": "IpArith_AVX256", + "PublicDescription": "Instructions per FP Arithmetic AVX* 256-bit = instruction (lower number means higher occurrence rate). May undercount due= to FMA double counting." + }, + { + "BriefDescription": "Instructions per FP Arithmetic AVX 512-bit in= struction (lower number means higher occurrence rate)", + "MetricExpr": "INST_RETIRED.ANY / ( FP_ARITH_INST_RETIRED.512B_PAC= KED_DOUBLE + FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE )", + "MetricGroup": "Flops;FpVector;InsType", + "MetricName": "IpArith_AVX512", + "PublicDescription": "Instructions per FP Arithmetic AVX 512-bit i= nstruction (lower number means higher occurrence rate). May undercount due = to FMA double counting." + }, { "BriefDescription": "Total number of retired Instructions, Sample = with: INST_RETIRED.PREC_DIST", "MetricExpr": "INST_RETIRED.ANY", "MetricGroup": "Summary;TmaL1", "MetricName": "Instructions" }, + { + "BriefDescription": "Average number of Uops issued by front-end wh= en it issued something", + "MetricExpr": "UOPS_ISSUED.ANY / cpu@UOPS_ISSUED.ANY\\,cmask\\=3D1= @", + "MetricGroup": "Fed;FetchBW", + "MetricName": "Fetch_UpC" + }, { "BriefDescription": "Fraction of Uops delivered by the DSB (aka De= coded ICache; or Uop Cache)", "MetricExpr": "IDQ.DSB_UOPS / (IDQ.DSB_UOPS + IDQ.MITE_UOPS + IDQ.= MS_UOPS)", - "MetricGroup": "DSB;FetchBW", + "MetricGroup": "DSB;Fed;FetchBW", "MetricName": "DSB_Coverage" }, { - "BriefDescription": "Actual Average Latency for L1 data-cache miss= demand loads (in core cycles)", + "BriefDescription": "Total penalty related to DSB (uop cache) miss= es - subset/see of/the Instruction_Fetch_BW Bottleneck.", + "MetricExpr": "(4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.COR= E / (4 * CPU_CLK_UNHALTED.THREAD)) * (DSB2MITE_SWITCHES.PENALTY_CYCLES / CP= U_CLK_UNHALTED.THREAD) / #(4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.C= ORE / (4 * CPU_CLK_UNHALTED.THREAD)) + ((IDQ_UOPS_NOT_DELIVERED.CORE / (4 *= CPU_CLK_UNHALTED.THREAD)) - (4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELI= V.CORE / (4 * CPU_CLK_UNHALTED.THREAD))) * (( IDQ.ALL_MITE_CYCLES_ANY_UOPS = - IDQ.ALL_MITE_CYCLES_4_UOPS ) / CPU_CLK_UNHALTED.THREAD / 2) / #((IDQ_UOPS= _NOT_DELIVERED.CORE / (4 * CPU_CLK_UNHALTED.THREAD)) - (4 * IDQ_UOPS_NOT_DE= LIVERED.CYCLES_0_UOPS_DELIV.CORE / (4 * CPU_CLK_UNHALTED.THREAD)))", + "MetricGroup": "DSBmiss;Fed", + "MetricName": "DSB_Misses_Cost" + }, + { + "BriefDescription": "Total penalty related to DSB (uop cache) miss= es - subset/see of/the Instruction_Fetch_BW Bottleneck.", + "MetricExpr": "(4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.COR= E / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THR= EAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))) * (DSB2MITE_SWITCHES.PENALTY_C= YCLES / CPU_CLK_UNHALTED.THREAD) / #(4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UO= PS_DELIV.CORE / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHA= LTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))) + ((IDQ_UOPS_NOT_D= ELIVERED.CORE / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHA= LTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))) - (4 * IDQ_UOPS_NO= T_DELIVERED.CYCLES_0_UOPS_DELIV.CORE / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2= ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK )= )))) * (( IDQ.ALL_MITE_CYCLES_ANY_UOPS - IDQ.ALL_MITE_CYCLES_4_UOPS ) / ( = ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE = / CPU_CLK_UNHALTED.REF_XCLK ) ) / 2) / #((IDQ_UOPS_NOT_DELIVERED.CORE / (4 = * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACT= IVE / CPU_CLK_UNHALTED.REF_XCLK ) ))) - (4 * IDQ_UOPS_NOT_DELIVERED.CYCLES_= 0_UOPS_DELIV.CORE / (4 * ( ( CPU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_= UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNHALTED.REF_XCLK ) ))))", + "MetricGroup": "DSBmiss;Fed_SMT", + "MetricName": "DSB_Misses_Cost_SMT" + }, + { + "BriefDescription": "Number of Instructions per non-speculative DS= B miss", + "MetricExpr": "INST_RETIRED.ANY / FRONTEND_RETIRED.ANY_DSB_MISS", + "MetricGroup": "DSBmiss;Fed", + "MetricName": "IpDSB_Miss_Ret" + }, + { + "BriefDescription": "Fraction of branches that are non-taken condi= tionals", + "MetricExpr": "BR_INST_RETIRED.NOT_TAKEN / BR_INST_RETIRED.ALL_BRA= NCHES", + "MetricGroup": "Bad;Branches;CodeGen;PGO", + "MetricName": "Cond_NT" + }, + { + "BriefDescription": "Fraction of branches that are taken condition= als", + "MetricExpr": "( BR_INST_RETIRED.CONDITIONAL - BR_INST_RETIRED.NOT= _TAKEN ) / BR_INST_RETIRED.ALL_BRANCHES", + "MetricGroup": "Bad;Branches;CodeGen;PGO", + "MetricName": "Cond_TK" + }, + { + "BriefDescription": "Fraction of branches that are CALL or RET", + "MetricExpr": "( BR_INST_RETIRED.NEAR_CALL + BR_INST_RETIRED.NEAR_= RETURN ) / BR_INST_RETIRED.ALL_BRANCHES", + "MetricGroup": "Bad;Branches", + "MetricName": "CallRet" + }, + { + "BriefDescription": "Fraction of branches that are unconditional (= direct or indirect) jumps", + "MetricExpr": "(BR_INST_RETIRED.NEAR_TAKEN - ( BR_INST_RETIRED.CON= DITIONAL - BR_INST_RETIRED.NOT_TAKEN ) - 2 * BR_INST_RETIRED.NEAR_CALL) / B= R_INST_RETIRED.ALL_BRANCHES", + "MetricGroup": "Bad;Branches", + "MetricName": "Jump" + }, + { + "BriefDescription": "Actual Average Latency for L1 data-cache miss= demand load instructions (in core cycles)", "MetricExpr": "L1D_PEND_MISS.PENDING / ( MEM_LOAD_RETIRED.L1_MISS = + MEM_LOAD_RETIRED.FB_HIT )", - "MetricGroup": "MemoryBound;MemoryLat", - "MetricName": "Load_Miss_Real_Latency" + "MetricGroup": "Mem;MemoryBound;MemoryLat", + "MetricName": "Load_Miss_Real_Latency", + "PublicDescription": "Actual Average Latency for L1 data-cache mis= s demand load instructions (in core cycles). Latency may be overestimated f= or multi-load instructions - e.g. repeat strings." }, { "BriefDescription": "Memory-Level-Parallelism (average number of L= 1 miss demand load when there is at least one such miss. Per-Logical Proces= sor)", "MetricExpr": "L1D_PEND_MISS.PENDING / L1D_PEND_MISS.PENDING_CYCLE= S", - "MetricGroup": "MemoryBound;MemoryBW", + "MetricGroup": "Mem;MemoryBound;MemoryBW", "MetricName": "MLP" }, - { - "BriefDescription": "Utilization of the core's Page Walker(s) serv= ing STLB misses triggered by instruction/Load/Store accesses", - "MetricConstraint": "NO_NMI_WATCHDOG", - "MetricExpr": "( ITLB_MISSES.WALK_PENDING + DTLB_LOAD_MISSES.WALK_= PENDING + DTLB_STORE_MISSES.WALK_PENDING + EPT.WALK_PENDING ) / ( 2 * CORE_= CLKS )", - "MetricGroup": "MemoryTLB", - "MetricName": "Page_Walks_Utilization" - }, { "BriefDescription": "Average data fill bandwidth to the L1 data ca= che [GB / sec]", "MetricExpr": "64 * L1D.REPLACEMENT / 1000000000 / duration_time", - "MetricGroup": "MemoryBW", + "MetricGroup": "Mem;MemoryBW", "MetricName": "L1D_Cache_Fill_BW" }, { "BriefDescription": "Average data fill bandwidth to the L2 cache [= GB / sec]", "MetricExpr": "64 * L2_LINES_IN.ALL / 1000000000 / duration_time", - "MetricGroup": "MemoryBW", + "MetricGroup": "Mem;MemoryBW", "MetricName": "L2_Cache_Fill_BW" }, { "BriefDescription": "Average per-core data fill bandwidth to the L= 3 cache [GB / sec]", "MetricExpr": "64 * LONGEST_LAT_CACHE.MISS / 1000000000 / duration= _time", - "MetricGroup": "MemoryBW", + "MetricGroup": "Mem;MemoryBW", "MetricName": "L3_Cache_Fill_BW" }, { "BriefDescription": "Average per-core data access bandwidth to the= L3 cache [GB / sec]", "MetricExpr": "64 * OFFCORE_REQUESTS.ALL_REQUESTS / 1000000000 / d= uration_time", - "MetricGroup": "MemoryBW;Offcore", + "MetricGroup": "Mem;MemoryBW;Offcore", "MetricName": "L3_Cache_Access_BW" }, { "BriefDescription": "L1 cache true misses per kilo instruction for= retired demand loads", "MetricExpr": "1000 * MEM_LOAD_RETIRED.L1_MISS / INST_RETIRED.ANY", - "MetricGroup": "CacheMisses", + "MetricGroup": "Mem;CacheMisses", "MetricName": "L1MPKI" }, + { + "BriefDescription": "L1 cache true misses per kilo instruction for= all demand loads (including speculative)", + "MetricExpr": "1000 * L2_RQSTS.ALL_DEMAND_DATA_RD / INST_RETIRED.A= NY", + "MetricGroup": "Mem;CacheMisses", + "MetricName": "L1MPKI_Load" + }, { "BriefDescription": "L2 cache true misses per kilo instruction for= retired demand loads", "MetricExpr": "1000 * MEM_LOAD_RETIRED.L2_MISS / INST_RETIRED.ANY", - "MetricGroup": "CacheMisses", + "MetricGroup": "Mem;Backend;CacheMisses", "MetricName": "L2MPKI" }, { "BriefDescription": "L2 cache misses per kilo instruction for all = request types (including speculative)", "MetricExpr": "1000 * L2_RQSTS.MISS / INST_RETIRED.ANY", - "MetricGroup": "CacheMisses;Offcore", + "MetricGroup": "Mem;CacheMisses;Offcore", "MetricName": "L2MPKI_All" }, + { + "BriefDescription": "L2 cache misses per kilo instruction for all = demand loads (including speculative)", + "MetricExpr": "1000 * L2_RQSTS.DEMAND_DATA_RD_MISS / INST_RETIRED.= ANY", + "MetricGroup": "Mem;CacheMisses", + "MetricName": "L2MPKI_Load" + }, { "BriefDescription": "L2 cache hits per kilo instruction for all re= quest types (including speculative)", "MetricExpr": "1000 * ( L2_RQSTS.REFERENCES - L2_RQSTS.MISS ) / IN= ST_RETIRED.ANY", - "MetricGroup": "CacheMisses", + "MetricGroup": "Mem;CacheMisses", "MetricName": "L2HPKI_All" }, + { + "BriefDescription": "L2 cache hits per kilo instruction for all de= mand loads (including speculative)", + "MetricExpr": "1000 * L2_RQSTS.DEMAND_DATA_RD_HIT / INST_RETIRED.A= NY", + "MetricGroup": "Mem;CacheMisses", + "MetricName": "L2HPKI_Load" + }, { "BriefDescription": "L3 cache true misses per kilo instruction for= retired demand loads", "MetricExpr": "1000 * MEM_LOAD_RETIRED.L3_MISS / INST_RETIRED.ANY", - "MetricGroup": "CacheMisses", + "MetricGroup": "Mem;CacheMisses", "MetricName": "L3MPKI" }, + { + "BriefDescription": "Fill Buffer (FB) true hits per kilo instructi= ons for retired demand loads", + "MetricExpr": "1000 * MEM_LOAD_RETIRED.FB_HIT / INST_RETIRED.ANY", + "MetricGroup": "Mem;CacheMisses", + "MetricName": "FB_HPKI" + }, + { + "BriefDescription": "Utilization of the core's Page Walker(s) serv= ing STLB misses triggered by instruction/Load/Store accesses", + "MetricConstraint": "NO_NMI_WATCHDOG", + "MetricExpr": "( ITLB_MISSES.WALK_PENDING + DTLB_LOAD_MISSES.WALK_= PENDING + DTLB_STORE_MISSES.WALK_PENDING + EPT.WALK_PENDING ) / ( 2 * CPU_C= LK_UNHALTED.THREAD )", + "MetricGroup": "Mem;MemoryTLB", + "MetricName": "Page_Walks_Utilization" + }, + { + "BriefDescription": "Utilization of the core's Page Walker(s) serv= ing STLB misses triggered by instruction/Load/Store accesses", + "MetricExpr": "( ITLB_MISSES.WALK_PENDING + DTLB_LOAD_MISSES.WALK_= PENDING + DTLB_STORE_MISSES.WALK_PENDING + EPT.WALK_PENDING ) / ( 2 * ( ( C= PU_CLK_UNHALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / C= PU_CLK_UNHALTED.REF_XCLK ) ) )", + "MetricGroup": "Mem;MemoryTLB_SMT", + "MetricName": "Page_Walks_Utilization_SMT" + }, { "BriefDescription": "Rate of silent evictions from the L2 cache pe= r Kilo instruction where the evicted lines are dropped (no writeback to L3 = or memory)", "MetricExpr": "1000 * L2_LINES_OUT.SILENT / INST_RETIRED.ANY", - "MetricGroup": "L2Evicts;Server", + "MetricGroup": "L2Evicts;Mem;Server", "MetricName": "L2_Evictions_Silent_PKI" }, { "BriefDescription": "Rate of non silent evictions from the L2 cach= e per Kilo instruction", "MetricExpr": "1000 * L2_LINES_OUT.NON_SILENT / INST_RETIRED.ANY", - "MetricGroup": "L2Evicts;Server", + "MetricGroup": "L2Evicts;Mem;Server", "MetricName": "L2_Evictions_NonSilent_PKI" }, { @@ -219,7 +532,7 @@ { "BriefDescription": "Giga Floating Point Operations Per Second", "MetricExpr": "( ( 1 * ( FP_ARITH_INST_RETIRED.SCALAR_SINGLE + FP_= ARITH_INST_RETIRED.SCALAR_DOUBLE ) + 2 * FP_ARITH_INST_RETIRED.128B_PACKED_= DOUBLE + 4 * ( FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE + FP_ARITH_INST_RET= IRED.256B_PACKED_DOUBLE ) + 8 * ( FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE = + FP_ARITH_INST_RETIRED.512B_PACKED_DOUBLE ) + 16 * FP_ARITH_INST_RETIRED.5= 12B_PACKED_SINGLE ) / 1000000000 ) / duration_time", - "MetricGroup": "Flops;HPC", + "MetricGroup": "Cor;Flops;HPC", "MetricName": "GFLOPs" }, { @@ -228,6 +541,48 @@ "MetricGroup": "Power", "MetricName": "Turbo_Utilization" }, + { + "BriefDescription": "Fraction of Core cycles where the core was ru= nning with power-delivery for baseline license level 0", + "MetricExpr": "CORE_POWER.LVL0_TURBO_LICENSE / CPU_CLK_UNHALTED.TH= READ", + "MetricGroup": "Power", + "MetricName": "Power_License0_Utilization", + "PublicDescription": "Fraction of Core cycles where the core was r= unning with power-delivery for baseline license level 0. This includes non= -AVX codes, SSE, AVX 128-bit, and low-current AVX 256-bit codes." + }, + { + "BriefDescription": "Fraction of Core cycles where the core was ru= nning with power-delivery for baseline license level 0. SMT version; use wh= en SMT is enabled and measuring per logical CPU.", + "MetricExpr": "CORE_POWER.LVL0_TURBO_LICENSE / 2 / ( ( CPU_CLK_UNH= ALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNH= ALTED.REF_XCLK ) )", + "MetricGroup": "Power_SMT", + "MetricName": "Power_License0_Utilization_SMT", + "PublicDescription": "Fraction of Core cycles where the core was r= unning with power-delivery for baseline license level 0. This includes non= -AVX codes, SSE, AVX 128-bit, and low-current AVX 256-bit codes. SMT versio= n; use when SMT is enabled and measuring per logical CPU." + }, + { + "BriefDescription": "Fraction of Core cycles where the core was ru= nning with power-delivery for license level 1", + "MetricExpr": "CORE_POWER.LVL1_TURBO_LICENSE / CPU_CLK_UNHALTED.TH= READ", + "MetricGroup": "Power", + "MetricName": "Power_License1_Utilization", + "PublicDescription": "Fraction of Core cycles where the core was r= unning with power-delivery for license level 1. This includes high current= AVX 256-bit instructions as well as low current AVX 512-bit instructions." + }, + { + "BriefDescription": "Fraction of Core cycles where the core was ru= nning with power-delivery for license level 1. SMT version; use when SMT is= enabled and measuring per logical CPU.", + "MetricExpr": "CORE_POWER.LVL1_TURBO_LICENSE / 2 / ( ( CPU_CLK_UNH= ALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNH= ALTED.REF_XCLK ) )", + "MetricGroup": "Power_SMT", + "MetricName": "Power_License1_Utilization_SMT", + "PublicDescription": "Fraction of Core cycles where the core was r= unning with power-delivery for license level 1. This includes high current= AVX 256-bit instructions as well as low current AVX 512-bit instructions. = SMT version; use when SMT is enabled and measuring per logical CPU." + }, + { + "BriefDescription": "Fraction of Core cycles where the core was ru= nning with power-delivery for license level 2 (introduced in SKX)", + "MetricExpr": "CORE_POWER.LVL2_TURBO_LICENSE / CPU_CLK_UNHALTED.TH= READ", + "MetricGroup": "Power", + "MetricName": "Power_License2_Utilization", + "PublicDescription": "Fraction of Core cycles where the core was r= unning with power-delivery for license level 2 (introduced in SKX). This i= ncludes high current AVX 512-bit instructions." + }, + { + "BriefDescription": "Fraction of Core cycles where the core was ru= nning with power-delivery for license level 2 (introduced in SKX). SMT vers= ion; use when SMT is enabled and measuring per logical CPU.", + "MetricExpr": "CORE_POWER.LVL2_TURBO_LICENSE / 2 / ( ( CPU_CLK_UNH= ALTED.THREAD / 2 ) * ( 1 + CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / CPU_CLK_UNH= ALTED.REF_XCLK ) )", + "MetricGroup": "Power_SMT", + "MetricName": "Power_License2_Utilization_SMT", + "PublicDescription": "Fraction of Core cycles where the core was r= unning with power-delivery for license level 2 (introduced in SKX). This i= ncludes high current AVX 512-bit instructions. SMT version; use when SMT is= enabled and measuring per logical CPU." + }, { "BriefDescription": "Fraction of cycles where both hardware Logica= l Processors were active", "MetricExpr": "1 - CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE / ( CPU_CLK_= UNHALTED.REF_XCLK_ANY / 2 ) if #SMT_on else 0", @@ -240,34 +595,46 @@ "MetricGroup": "OS", "MetricName": "Kernel_Utilization" }, + { + "BriefDescription": "Cycles Per Instruction for the Operating Syst= em (OS) Kernel mode", + "MetricExpr": "CPU_CLK_UNHALTED.THREAD_P:k / INST_RETIRED.ANY_P:k", + "MetricGroup": "OS", + "MetricName": "Kernel_CPI" + }, { "BriefDescription": "Average external Memory Bandwidth Use for rea= ds and writes [GB / sec]", "MetricExpr": "( 64 * ( uncore_imc@cas_count_read@ + uncore_imc@ca= s_count_write@ ) / 1000000000 ) / duration_time", - "MetricGroup": "HPC;MemoryBW;SoC", + "MetricGroup": "HPC;Mem;MemoryBW;SoC", "MetricName": "DRAM_BW_Use" }, { "BriefDescription": "Average latency of data read request to exter= nal memory (in nanoseconds). Accounts for demand loads and L1/L2 prefetches= ", "MetricExpr": "1000000000 * ( cha@event\\=3D0x36\\,umask\\=3D0x21\= \,config\\=3D0x40433@ / cha@event\\=3D0x35\\,umask\\=3D0x21\\,config\\=3D0x= 40433@ ) / ( cha_0@event\\=3D0x0@ / duration_time )", - "MetricGroup": "MemoryLat;SoC", + "MetricGroup": "Mem;MemoryLat;SoC", "MetricName": "MEM_Read_Latency" }, { "BriefDescription": "Average number of parallel data read requests= to external memory. Accounts for demand loads and L1/L2 prefetches", "MetricExpr": "cha@event\\=3D0x36\\,umask\\=3D0x21\\,config\\=3D0x= 40433@ / cha@event\\=3D0x36\\,umask\\=3D0x21\\,config\\=3D0x40433\\,thresh\= \=3D1@", - "MetricGroup": "MemoryBW;SoC", + "MetricGroup": "Mem;MemoryBW;SoC", "MetricName": "MEM_Parallel_Reads" }, + { + "BriefDescription": "Average latency of data read request to exter= nal DRAM memory [in nanoseconds]. Accounts for demand loads and L1/L2 data-= read prefetches", + "MetricExpr": "1000000000 * ( UNC_M_RPQ_OCCUPANCY / UNC_M_RPQ_INSE= RTS ) / imc_0@event\\=3D0x0@", + "MetricGroup": "Mem;MemoryLat;SoC;Server", + "MetricName": "MEM_DRAM_Read_Latency" + }, { "BriefDescription": "Average IO (network or disk) Bandwidth Use fo= r Writes [GB / sec]", "MetricExpr": "( UNC_IIO_DATA_REQ_OF_CPU.MEM_READ.PART0 + UNC_IIO_= DATA_REQ_OF_CPU.MEM_READ.PART1 + UNC_IIO_DATA_REQ_OF_CPU.MEM_READ.PART2 + U= NC_IIO_DATA_REQ_OF_CPU.MEM_READ.PART3 ) * 4 / 1000000000 / duration_time", - "MetricGroup": "IoBW;SoC;Server", + "MetricGroup": "IoBW;Mem;SoC;Server", "MetricName": "IO_Write_BW" }, { "BriefDescription": "Average IO (network or disk) Bandwidth Use fo= r Reads [GB / sec]", "MetricExpr": "( UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART0 + UNC_IIO= _DATA_REQ_OF_CPU.MEM_WRITE.PART1 + UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART2 = + UNC_IIO_DATA_REQ_OF_CPU.MEM_WRITE.PART3 ) * 4 / 1000000000 / duration_tim= e", - "MetricGroup": "IoBW;SoC;Server", + "MetricGroup": "IoBW;Mem;SoC;Server", "MetricName": "IO_Read_BW" }, { diff --git a/tools/perf/pmu-events/arch/x86/skylakex/uncore-other.json b/to= ols/perf/pmu-events/arch/x86/skylakex/uncore-other.json index 6ed92bc5c129..06c5ca26ca3f 100644 --- a/tools/perf/pmu-events/arch/x86/skylakex/uncore-other.json +++ b/tools/perf/pmu-events/arch/x86/skylakex/uncore-other.json @@ -537,6 +537,18 @@ "PublicDescription": "Counts clockticks of the 1GHz trafiic contro= ller clock in the IIO unit.", "Unit": "IIO" }, + { + "BriefDescription": "PCIe Completion Buffer Inserts of completions= with data: Part 0-3", + "Counter": "0,1,2,3", + "EventCode": "0xC2", + "EventName": "UNC_IIO_COMP_BUF_INSERTS.CMPD.ALL_PARTS", + "FCMask": "0x4", + "PerPkg": "1", + "PortMask": "0x0f", + "PublicDescription": "PCIe Completion Buffer Inserts of completion= s with data: Part 0-3", + "UMask": "0x03", + "Unit": "IIO" + }, { "BriefDescription": "PCIe Completion Buffer Inserts of completions= with data: Part 0", "Counter": "0,1,2,3", @@ -585,6 +597,17 @@ "UMask": "0x03", "Unit": "IIO" }, + { + "BriefDescription": "PCIe Completion Buffer occupancy of completio= ns with data: Part 0-3", + "Counter": "2,3", + "EventCode": "0xD5", + "EventName": "UNC_IIO_COMP_BUF_OCCUPANCY.CMPD.ALL_PARTS", + "FCMask": "0x04", + "PerPkg": "1", + "PublicDescription": "PCIe Completion Buffer occupancy of completi= ons with data: Part 0-3", + "UMask": "0x0f", + "Unit": "IIO" + }, { "BriefDescription": "PCIe Completion Buffer occupancy of completio= ns with data: Part 0", "Counter": "2,3", diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c index cb32f9e27d5d..5a39b3fdcac4 100644 --- a/tools/testing/cxl/test/cxl.c +++ b/tools/testing/cxl/test/cxl.c @@ -488,7 +488,7 @@ static __init int cxl_test_init(void) =20 for (i =3D 0; i < ARRAY_SIZE(cxl_root_port); i++) { struct platform_device *bridge =3D - cxl_host_bridge[i / NR_CXL_ROOT_PORTS]; + cxl_host_bridge[i % ARRAY_SIZE(cxl_host_bridge)]; struct platform_device *pdev; =20 pdev =3D platform_device_alloc("cxl_root_port", i); diff --git a/tools/testing/selftests/bpf/prog_tests/bind_perm.c b/tools/tes= ting/selftests/bpf/prog_tests/bind_perm.c index d0f06e40c16d..eac71fbb24ce 100644 --- a/tools/testing/selftests/bpf/prog_tests/bind_perm.c +++ b/tools/testing/selftests/bpf/prog_tests/bind_perm.c @@ -1,13 +1,24 @@ // SPDX-License-Identifier: GPL-2.0 -#include -#include "bind_perm.skel.h" - +#define _GNU_SOURCE +#include +#include #include #include #include =20 +#include "test_progs.h" +#include "bind_perm.skel.h" + static int duration; =20 +static int create_netns(void) +{ + if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns")) + return -1; + + return 0; +} + void try_bind(int family, int port, int expected_errno) { struct sockaddr_storage addr =3D {}; @@ -75,6 +86,9 @@ void test_bind_perm(void) struct bind_perm *skel; int cgroup_fd; =20 + if (create_netns()) + return; + cgroup_fd =3D test__join_cgroup("/bind_perm"); if (CHECK(cgroup_fd < 0, "cg-join", "errno %d", errno)) return; diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/s= elftests/bpf/progs/bpf_misc.h new file mode 100644 index 000000000000..5bb11fe595a4 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/bpf_misc.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __BPF_MISC_H__ +#define __BPF_MISC_H__ + +#if defined(__TARGET_ARCH_x86) +#define SYSCALL_WRAPPER 1 +#define SYS_PREFIX "__x64_" +#elif defined(__TARGET_ARCH_s390) +#define SYSCALL_WRAPPER 1 +#define SYS_PREFIX "__s390x_" +#elif defined(__TARGET_ARCH_arm64) +#define SYSCALL_WRAPPER 1 +#define SYS_PREFIX "__arm64_" +#else +#define SYSCALL_WRAPPER 0 +#define SYS_PREFIX "__se_" +#endif + +#endif diff --git a/tools/testing/selftests/bpf/progs/test_probe_user.c b/tools/te= sting/selftests/bpf/progs/test_probe_user.c index 8812a90da4eb..702578a5e496 100644 --- a/tools/testing/selftests/bpf/progs/test_probe_user.c +++ b/tools/testing/selftests/bpf/progs/test_probe_user.c @@ -7,20 +7,7 @@ =20 #include #include - -#if defined(__TARGET_ARCH_x86) -#define SYSCALL_WRAPPER 1 -#define SYS_PREFIX "__x64_" -#elif defined(__TARGET_ARCH_s390) -#define SYSCALL_WRAPPER 1 -#define SYS_PREFIX "__s390x_" -#elif defined(__TARGET_ARCH_arm64) -#define SYSCALL_WRAPPER 1 -#define SYS_PREFIX "__arm64_" -#else -#define SYSCALL_WRAPPER 0 -#define SYS_PREFIX "" -#endif +#include "bpf_misc.h" =20 static struct sockaddr_in old; =20 diff --git a/tools/testing/selftests/bpf/progs/test_sock_fields.c b/tools/t= esting/selftests/bpf/progs/test_sock_fields.c index 81b57b9aaaea..7967348b11af 100644 --- a/tools/testing/selftests/bpf/progs/test_sock_fields.c +++ b/tools/testing/selftests/bpf/progs/test_sock_fields.c @@ -113,7 +113,7 @@ static void tpcpy(struct bpf_tcp_sock *dst, =20 #define RET_LOG() ({ \ linum =3D __LINE__; \ - bpf_map_update_elem(&linum_map, &linum_idx, &linum, BPF_NOEXIST); \ + bpf_map_update_elem(&linum_map, &linum_idx, &linum, BPF_ANY); \ return CG_OK; \ }) =20 diff --git a/tools/testing/selftests/bpf/test_lirc_mode2.sh b/tools/testing= /selftests/bpf/test_lirc_mode2.sh index ec4e15948e40..5252b91f48a1 100755 --- a/tools/testing/selftests/bpf/test_lirc_mode2.sh +++ b/tools/testing/selftests/bpf/test_lirc_mode2.sh @@ -3,6 +3,7 @@ =20 # Kselftest framework requirement - SKIP code is 4. ksft_skip=3D4 +ret=3D$ksft_skip =20 msg=3D"skip all tests:" if [ $UID !=3D 0 ]; then @@ -25,7 +26,7 @@ do fi done =20 -if [ -n $LIRCDEV ]; +if [ -n "$LIRCDEV" ]; then TYPE=3Dlirc_mode2 ./test_lirc_mode2_user $LIRCDEV $INPUTDEV @@ -36,3 +37,5 @@ then echo -e ${GREEN}"PASS: $TYPE"${NC} fi fi + +exit $ret diff --git a/tools/testing/selftests/bpf/test_lwt_ip_encap.sh b/tools/testi= ng/selftests/bpf/test_lwt_ip_encap.sh index b497bb85b667..6c69c42b1d60 100755 --- a/tools/testing/selftests/bpf/test_lwt_ip_encap.sh +++ b/tools/testing/selftests/bpf/test_lwt_ip_encap.sh @@ -120,6 +120,14 @@ setup() ip netns exec ${NS2} sysctl -wq net.ipv4.conf.default.rp_filter=3D0 ip netns exec ${NS3} sysctl -wq net.ipv4.conf.default.rp_filter=3D0 =20 + # disable IPv6 DAD because it sometimes takes too long and fails tests + ip netns exec ${NS1} sysctl -wq net.ipv6.conf.all.accept_dad=3D0 + ip netns exec ${NS2} sysctl -wq net.ipv6.conf.all.accept_dad=3D0 + ip netns exec ${NS3} sysctl -wq net.ipv6.conf.all.accept_dad=3D0 + ip netns exec ${NS1} sysctl -wq net.ipv6.conf.default.accept_dad=3D0 + ip netns exec ${NS2} sysctl -wq net.ipv6.conf.default.accept_dad=3D0 + ip netns exec ${NS3} sysctl -wq net.ipv6.conf.default.accept_dad=3D0 + ip link add veth1 type veth peer name veth2 ip link add veth3 type veth peer name veth4 ip link add veth5 type veth peer name veth6 @@ -289,7 +297,7 @@ test_ping() ip netns exec ${NS1} ping -c 1 -W 1 -I veth1 ${IPv4_DST} 2>&1 > /dev/nu= ll RET=3D$? elif [ "${PROTO}" =3D=3D "IPv6" ] ; then - ip netns exec ${NS1} ping6 -c 1 -W 6 -I veth1 ${IPv6_DST} 2>&1 > /dev/nu= ll + ip netns exec ${NS1} ping6 -c 1 -W 1 -I veth1 ${IPv6_DST} 2>&1 > /dev/nu= ll RET=3D$? else echo " test_ping: unknown PROTO: ${PROTO}" diff --git a/tools/testing/selftests/bpf/test_xdp_redirect_multi.sh b/tools= /testing/selftests/bpf/test_xdp_redirect_multi.sh index 05f872740999..cc57cb87e65f 100755 --- a/tools/testing/selftests/bpf/test_xdp_redirect_multi.sh +++ b/tools/testing/selftests/bpf/test_xdp_redirect_multi.sh @@ -32,6 +32,11 @@ DRV_MODE=3D"xdpgeneric xdpdrv xdpegress" PASS=3D0 FAIL=3D0 LOG_DIR=3D$(mktemp -d) +declare -a NS +NS[0]=3D"ns0-$(mktemp -u XXXXXX)" +NS[1]=3D"ns1-$(mktemp -u XXXXXX)" +NS[2]=3D"ns2-$(mktemp -u XXXXXX)" +NS[3]=3D"ns3-$(mktemp -u XXXXXX)" =20 test_pass() { @@ -47,11 +52,9 @@ test_fail() =20 clean_up() { - for i in $(seq $NUM); do - ip link del veth$i 2> /dev/null - ip netns del ns$i 2> /dev/null + for i in $(seq 0 $NUM); do + ip netns del ${NS[$i]} 2> /dev/null done - ip netns del ns0 2> /dev/null } =20 # Kselftest framework requirement - SKIP code is 4. @@ -79,23 +82,22 @@ setup_ns() mode=3D"xdpdrv" fi =20 - ip netns add ns0 + ip netns add ${NS[0]} for i in $(seq $NUM); do - ip netns add ns$i - ip -n ns$i link add veth0 index 2 type veth \ - peer name veth$i netns ns0 index $((1 + $i)) - ip -n ns0 link set veth$i up - ip -n ns$i link set veth0 up - - ip -n ns$i addr add 192.0.2.$i/24 dev veth0 - ip -n ns$i addr add 2001:db8::$i/64 dev veth0 + ip netns add ${NS[$i]} + ip -n ${NS[$i]} link add veth0 type veth peer name veth$i netns ${NS[0]} + ip -n ${NS[$i]} link set veth0 up + ip -n ${NS[0]} link set veth$i up + + ip -n ${NS[$i]} addr add 192.0.2.$i/24 dev veth0 + ip -n ${NS[$i]} addr add 2001:db8::$i/64 dev veth0 # Add a neigh entry for IPv4 ping test - ip -n ns$i neigh add 192.0.2.253 lladdr 00:00:00:00:00:01 dev veth0 - ip -n ns$i link set veth0 $mode obj \ + ip -n ${NS[$i]} neigh add 192.0.2.253 lladdr 00:00:00:00:00:01 dev veth0 + ip -n ${NS[$i]} link set veth0 $mode obj \ xdp_dummy.o sec xdp &> /dev/null || \ { test_fail "Unable to load dummy xdp" && exit 1; } IFACES=3D"$IFACES veth$i" - veth_mac[$i]=3D$(ip -n ns0 link show veth$i | awk '/link\/ether/ {print = $2}') + veth_mac[$i]=3D$(ip -n ${NS[0]} link show veth$i | awk '/link\/ether/ {p= rint $2}') done } =20 @@ -104,10 +106,10 @@ do_egress_tests() local mode=3D$1 =20 # mac test - ip netns exec ns2 tcpdump -e -i veth0 -nn -l -e &> ${LOG_DIR}/mac_ns1-2_$= {mode}.log & - ip netns exec ns3 tcpdump -e -i veth0 -nn -l -e &> ${LOG_DIR}/mac_ns1-3_$= {mode}.log & + ip netns exec ${NS[2]} tcpdump -e -i veth0 -nn -l -e &> ${LOG_DIR}/mac_ns= 1-2_${mode}.log & + ip netns exec ${NS[3]} tcpdump -e -i veth0 -nn -l -e &> ${LOG_DIR}/mac_ns= 1-3_${mode}.log & sleep 0.5 - ip netns exec ns1 ping 192.0.2.254 -i 0.1 -c 4 &> /dev/null + ip netns exec ${NS[1]} ping 192.0.2.254 -i 0.1 -c 4 &> /dev/null sleep 0.5 pkill tcpdump =20 @@ -123,18 +125,18 @@ do_ping_tests() local mode=3D$1 =20 # ping6 test: echo request should be redirect back to itself, not others - ip netns exec ns1 ip neigh add 2001:db8::2 dev veth0 lladdr 00:00:00:00:0= 0:02 + ip netns exec ${NS[1]} ip neigh add 2001:db8::2 dev veth0 lladdr 00:00:00= :00:00:02 =20 - ip netns exec ns1 tcpdump -i veth0 -nn -l -e &> ${LOG_DIR}/ns1-1_${mode}.= log & - ip netns exec ns2 tcpdump -i veth0 -nn -l -e &> ${LOG_DIR}/ns1-2_${mode}.= log & - ip netns exec ns3 tcpdump -i veth0 -nn -l -e &> ${LOG_DIR}/ns1-3_${mode}.= log & + ip netns exec ${NS[1]} tcpdump -i veth0 -nn -l -e &> ${LOG_DIR}/ns1-1_${m= ode}.log & + ip netns exec ${NS[2]} tcpdump -i veth0 -nn -l -e &> ${LOG_DIR}/ns1-2_${m= ode}.log & + ip netns exec ${NS[3]} tcpdump -i veth0 -nn -l -e &> ${LOG_DIR}/ns1-3_${m= ode}.log & sleep 0.5 # ARP test - ip netns exec ns1 arping -q -c 2 -I veth0 192.0.2.254 + ip netns exec ${NS[1]} arping -q -c 2 -I veth0 192.0.2.254 # IPv4 test - ip netns exec ns1 ping 192.0.2.253 -i 0.1 -c 4 &> /dev/null + ip netns exec ${NS[1]} ping 192.0.2.253 -i 0.1 -c 4 &> /dev/null # IPv6 test - ip netns exec ns1 ping6 2001:db8::2 -i 0.1 -c 2 &> /dev/null + ip netns exec ${NS[1]} ping6 2001:db8::2 -i 0.1 -c 2 &> /dev/null sleep 0.5 pkill tcpdump =20 @@ -180,7 +182,7 @@ do_tests() xdpgeneric) drv_p=3D"-S";; esac =20 - ip netns exec ns0 ./xdp_redirect_multi $drv_p $IFACES &> ${LOG_DIR}/xdp_r= edirect_${mode}.log & + ip netns exec ${NS[0]} ./xdp_redirect_multi $drv_p $IFACES &> ${LOG_DIR}/= xdp_redirect_${mode}.log & xdp_pid=3D$! sleep 1 if ! ps -p $xdp_pid > /dev/null; then @@ -197,10 +199,10 @@ do_tests() kill $xdp_pid } =20 -trap clean_up EXIT - check_env =20 +trap clean_up EXIT + for mode in ${DRV_MODE}; do setup_ns $mode do_tests $mode diff --git a/tools/testing/selftests/bpf/xdpxceiver.c b/tools/testing/selft= ests/bpf/xdpxceiver.c index 621342ec30c4..37d4873d9a2e 100644 --- a/tools/testing/selftests/bpf/xdpxceiver.c +++ b/tools/testing/selftests/bpf/xdpxceiver.c @@ -902,7 +902,10 @@ static bool rx_stats_are_valid(struct ifobject *ifobje= ct) return true; case STAT_TEST_RX_FULL: xsk_stat =3D stats.rx_ring_full; - expected_stat -=3D RX_FULL_RXQSIZE; + if (ifobject->umem->num_frames < XSK_RING_PROD__DEFAULT_NUM_DESCS) + expected_stat =3D ifobject->umem->num_frames - RX_FULL_RXQSIZE; + else + expected_stat =3D XSK_RING_PROD__DEFAULT_NUM_DESCS - RX_FULL_RXQSIZE; break; case STAT_TEST_RX_FILL_EMPTY: xsk_stat =3D stats.rx_fill_ring_empty_descs; diff --git a/tools/testing/selftests/lkdtm/config b/tools/testing/selftests= /lkdtm/config index a26a3fa9e925..8bd847f0463c 100644 --- a/tools/testing/selftests/lkdtm/config +++ b/tools/testing/selftests/lkdtm/config @@ -6,6 +6,7 @@ CONFIG_HARDENED_USERCOPY=3Dy # CONFIG_HARDENED_USERCOPY_FALLBACK is not set CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT=3Dy CONFIG_INIT_ON_ALLOC_DEFAULT_ON=3Dy +CONFIG_UBSAN=3Dy CONFIG_UBSAN_BOUNDS=3Dy CONFIG_UBSAN_TRAP=3Dy CONFIG_STACKPROTECTOR_STRONG=3Dy diff --git a/tools/testing/selftests/net/af_unix/test_unix_oob.c b/tools/te= sting/selftests/net/af_unix/test_unix_oob.c index 3dece8b29253..b57e91e1c3f2 100644 --- a/tools/testing/selftests/net/af_unix/test_unix_oob.c +++ b/tools/testing/selftests/net/af_unix/test_unix_oob.c @@ -218,10 +218,10 @@ main(int argc, char **argv) =20 /* Test 1: * veriyf that SIGURG is - * delivered and 63 bytes are - * read and oob is '@' + * delivered, 63 bytes are + * read, oob is '@', and POLLPRI works. */ - wait_for_data(pfd, POLLIN | POLLPRI); + wait_for_data(pfd, POLLPRI); read_oob(pfd, &oob); len =3D read_data(pfd, buf, 1024); if (!signal_recvd || len !=3D 63 || oob !=3D '@') { diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.sh b/tools/tes= ting/selftests/net/mptcp/mptcp_connect.sh index 559173a8e387..d75fa97609c1 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_connect.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.sh @@ -445,6 +445,8 @@ do_transfer() local stat_ackrx_last_l=3D$(get_mib_counter "${listener_ns}" "MPTcpExtMPC= apableACKRX") local stat_cookietx_last=3D$(get_mib_counter "${listener_ns}" "TcpExtSync= ookiesSent") local stat_cookierx_last=3D$(get_mib_counter "${listener_ns}" "TcpExtSync= ookiesRecv") + local stat_csum_err_s=3D$(get_mib_counter "${listener_ns}" "MPTcpExtDataC= sumErr") + local stat_csum_err_c=3D$(get_mib_counter "${connector_ns}" "MPTcpExtData= CsumErr") =20 timeout ${timeout_test} \ ip netns exec ${listener_ns} \ @@ -537,6 +539,23 @@ do_transfer() fi fi =20 + if $checksum; then + local csum_err_s=3D$(get_mib_counter "${listener_ns}" "MPTcpExtDataCsumE= rr") + local csum_err_c=3D$(get_mib_counter "${connector_ns}" "MPTcpExtDataCsum= Err") + + local csum_err_s_nr=3D$((csum_err_s - stat_csum_err_s)) + if [ $csum_err_s_nr -gt 0 ]; then + printf "[ FAIL ]\nserver got $csum_err_s_nr data checksum error[s]" + rets=3D1 + fi + + local csum_err_c_nr=3D$((csum_err_c - stat_csum_err_c)) + if [ $csum_err_c_nr -gt 0 ]; then + printf "[ FAIL ]\nclient got $csum_err_c_nr data checksum error[s]" + retc=3D1 + fi + fi + if [ $retc -eq 0 ] && [ $rets -eq 0 ]; then printf "[ OK ]" fi diff --git a/tools/testing/selftests/net/test_vxlan_under_vrf.sh b/tools/te= sting/selftests/net/test_vxlan_under_vrf.sh index ea5a7a808f12..1fd1250ebc66 100755 --- a/tools/testing/selftests/net/test_vxlan_under_vrf.sh +++ b/tools/testing/selftests/net/test_vxlan_under_vrf.sh @@ -120,11 +120,11 @@ echo "[ OK ]" =20 # Move the underlay to a non-default VRF ip -netns hv-1 link set veth0 vrf vrf-underlay -ip -netns hv-1 link set veth0 down -ip -netns hv-1 link set veth0 up +ip -netns hv-1 link set vxlan0 down +ip -netns hv-1 link set vxlan0 up ip -netns hv-2 link set veth0 vrf vrf-underlay -ip -netns hv-2 link set veth0 down -ip -netns hv-2 link set veth0 up +ip -netns hv-2 link set vxlan0 down +ip -netns hv-2 link set vxlan0 up =20 echo -n "Check VM connectivity through VXLAN (underlay in a VRF) = " ip netns exec vm-1 ping -c 1 -W 1 10.0.0.2 &> /dev/null || (echo "[FAIL]";= false) diff --git a/tools/testing/selftests/net/timestamping.c b/tools/testing/sel= ftests/net/timestamping.c index aee631c5284e..044bc0e9ed81 100644 --- a/tools/testing/selftests/net/timestamping.c +++ b/tools/testing/selftests/net/timestamping.c @@ -325,8 +325,8 @@ int main(int argc, char **argv) struct ifreq device; struct ifreq hwtstamp; struct hwtstamp_config hwconfig, hwconfig_requested; - struct so_timestamping so_timestamping_get =3D { 0, -1 }; - struct so_timestamping so_timestamping =3D { 0, -1 }; + struct so_timestamping so_timestamping_get =3D { 0, 0 }; + struct so_timestamping so_timestamping =3D { 0, 0 }; struct sockaddr_in addr; struct ip_mreq imr; struct in_addr iaddr; diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/ne= t/tls.c index 6e468e0f42f7..5d70b04c482c 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -683,6 +683,9 @@ TEST_F(tls, splice_cmsg_to_pipe) char buf[10]; int p[2]; =20 + if (self->notls) + SKIP(return, "no TLS support"); + ASSERT_GE(pipe(p), 0); EXPECT_EQ(tls_send_cmsg(self->fd, 100, test_str, send_len, 0), 10); EXPECT_EQ(splice(self->cfd, NULL, p[1], NULL, send_len, 0), -1); @@ -703,6 +706,9 @@ TEST_F(tls, splice_dec_cmsg_to_pipe) char buf[10]; int p[2]; =20 + if (self->notls) + SKIP(return, "no TLS support"); + ASSERT_GE(pipe(p), 0); EXPECT_EQ(tls_send_cmsg(self->fd, 100, test_str, send_len, 0), 10); EXPECT_EQ(recv(self->cfd, buf, send_len, 0), -1); diff --git a/tools/testing/selftests/rcutorture/bin/torture.sh b/tools/test= ing/selftests/rcutorture/bin/torture.sh index eae88aacca2a..b2929fb15f7e 100755 --- a/tools/testing/selftests/rcutorture/bin/torture.sh +++ b/tools/testing/selftests/rcutorture/bin/torture.sh @@ -71,8 +71,8 @@ usage () { echo " --configs-rcutorture \"config-file list w/ repeat factor (3*= TINY01)\"" echo " --configs-locktorture \"config-file list w/ repeat factor (1= 0*LOCK01)\"" echo " --configs-scftorture \"config-file list w/ repeat factor (2*= CFLIST)\"" - echo " --doall" - echo " --doallmodconfig / --do-no-allmodconfig" + echo " --do-all" + echo " --do-allmodconfig / --do-no-allmodconfig" echo " --do-clocksourcewd / --do-no-clocksourcewd" echo " --do-kasan / --do-no-kasan" echo " --do-kcsan / --do-no-kcsan" diff --git a/tools/testing/selftests/sgx/Makefile b/tools/testing/selftests= /sgx/Makefile index 7f12d55b97f8..472b27ccd7dc 100644 --- a/tools/testing/selftests/sgx/Makefile +++ b/tools/testing/selftests/sgx/Makefile @@ -4,7 +4,7 @@ include ../lib.mk =20 .PHONY: all clean =20 -CAN_BUILD_X86_64 :=3D $(shell ../x86/check_cc.sh $(CC) \ +CAN_BUILD_X86_64 :=3D $(shell ../x86/check_cc.sh "$(CC)" \ ../x86/trivial_64bit_program.c) =20 ifndef OBJCOPY diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/= vm/Makefile index 1607322a112c..1530c3e0242e 100644 --- a/tools/testing/selftests/vm/Makefile +++ b/tools/testing/selftests/vm/Makefile @@ -1,6 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 # Makefile for vm selftests =20 +LOCAL_HDRS +=3D $(selfdir)/vm/local_config.h $(top_srcdir)/mm/gup_test.h + include local_config.mk =20 uname_M :=3D $(shell uname -m 2>/dev/null || echo not) @@ -49,9 +51,9 @@ TEST_GEN_FILES +=3D split_huge_page_test TEST_GEN_FILES +=3D ksm_tests =20 ifeq ($(MACHINE),x86_64) -CAN_BUILD_I386 :=3D $(shell ./../x86/check_cc.sh $(CC) ../x86/trivial_32bi= t_program.c -m32) -CAN_BUILD_X86_64 :=3D $(shell ./../x86/check_cc.sh $(CC) ../x86/trivial_64= bit_program.c) -CAN_BUILD_WITH_NOPIE :=3D $(shell ./../x86/check_cc.sh $(CC) ../x86/trivia= l_program.c -no-pie) +CAN_BUILD_I386 :=3D $(shell ./../x86/check_cc.sh "$(CC)" ../x86/trivial_32= bit_program.c -m32) +CAN_BUILD_X86_64 :=3D $(shell ./../x86/check_cc.sh "$(CC)" ../x86/trivial_= 64bit_program.c) +CAN_BUILD_WITH_NOPIE :=3D $(shell ./../x86/check_cc.sh "$(CC)" ../x86/triv= ial_program.c -no-pie) =20 TARGETS :=3D protection_keys BINARIES_32 :=3D $(TARGETS:%=3D%_32) @@ -140,10 +142,6 @@ endif =20 $(OUTPUT)/mlock-random-test $(OUTPUT)/memfd_secret: LDLIBS +=3D -lcap =20 -$(OUTPUT)/gup_test: ../../../../mm/gup_test.h - -$(OUTPUT)/hmm-tests: local_config.h - # HMM_EXTRA_LIBS may get set in local_config.mk, or it may be left empty. $(OUTPUT)/hmm-tests: LDLIBS +=3D $(HMM_EXTRA_LIBS) =20 diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests= /x86/Makefile index 8a1f62ab3c8e..53df7d3893d3 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -6,9 +6,9 @@ include ../lib.mk .PHONY: all all_32 all_64 warn_32bit_failure clean =20 UNAME_M :=3D $(shell uname -m) -CAN_BUILD_I386 :=3D $(shell ./check_cc.sh $(CC) trivial_32bit_program.c -m= 32) -CAN_BUILD_X86_64 :=3D $(shell ./check_cc.sh $(CC) trivial_64bit_program.c) -CAN_BUILD_WITH_NOPIE :=3D $(shell ./check_cc.sh $(CC) trivial_program.c -n= o-pie) +CAN_BUILD_I386 :=3D $(shell ./check_cc.sh "$(CC)" trivial_32bit_program.c = -m32) +CAN_BUILD_X86_64 :=3D $(shell ./check_cc.sh "$(CC)" trivial_64bit_program.= c) +CAN_BUILD_WITH_NOPIE :=3D $(shell ./check_cc.sh "$(CC)" trivial_program.c = -no-pie) =20 TARGETS_C_BOTHBITS :=3D single_step_syscall sysret_ss_attrs syscall_nt tes= t_mremap_vdso \ check_initial_reg_state sigreturn iopl ioperm \ diff --git a/tools/testing/selftests/x86/check_cc.sh b/tools/testing/selfte= sts/x86/check_cc.sh index 3e2089c8cf54..8c669c0d662e 100755 --- a/tools/testing/selftests/x86/check_cc.sh +++ b/tools/testing/selftests/x86/check_cc.sh @@ -7,7 +7,7 @@ CC=3D"$1" TESTPROG=3D"$2" shift 2 =20 -if "$CC" -o /dev/null "$TESTPROG" -O0 "$@" 2>/dev/null; then +if [ -n "$CC" ] && $CC -o /dev/null "$TESTPROG" -O0 "$@" 2>/dev/null; then echo 1 else echo 0 diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c index cb3f29c09aff..23f142af544a 100644 --- a/tools/virtio/virtio_test.c +++ b/tools/virtio/virtio_test.c @@ -130,6 +130,7 @@ static void vdev_info_init(struct vdev_info* dev, unsig= ned long long features) memset(dev, 0, sizeof *dev); dev->vdev.features =3D features; INIT_LIST_HEAD(&dev->vdev.vqs); + spin_lock_init(&dev->vdev.vqs_list_lock); dev->buf_size =3D 1024; dev->buf =3D malloc(dev->buf_size); assert(dev->buf); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 6ae9e04d0585..74798e50e3f9 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -117,6 +117,8 @@ EXPORT_SYMBOL_GPL(kvm_debugfs_dir); =20 static const struct file_operations stat_fops_per_vm; =20 +static struct file_operations kvm_chardev_ops; + static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl, unsigned long arg); #ifdef CONFIG_KVM_COMPAT @@ -1107,6 +1109,16 @@ static struct kvm *kvm_create_vm(unsigned long type) preempt_notifier_inc(); kvm_init_pm_notifier(kvm); =20 + /* + * When the fd passed to this ioctl() is opened it pins the module, + * but try_module_get() also prevents getting a reference if the module + * is in MODULE_STATE_GOING (e.g. if someone ran "rmmod --wait"). + */ + if (!try_module_get(kvm_chardev_ops.owner)) { + r =3D -ENODEV; + goto out_err; + } + return kvm; =20 out_err: @@ -1196,6 +1208,7 @@ static void kvm_destroy_vm(struct kvm *kvm) preempt_notifier_dec(); hardware_disable_all(); mmdrop(mm); + module_put(kvm_chardev_ops.owner); } =20 void kvm_get_kvm(struct kvm *kvm)