* Re: Linux 7.0.10
2026-05-23 11:46 Linux 7.0.10 Greg Kroah-Hartman
@ 2026-05-23 11:46 ` Greg Kroah-Hartman
0 siblings, 0 replies; 2+ messages in thread
From: Greg Kroah-Hartman @ 2026-05-23 11:46 UTC (permalink / raw)
To: linux-kernel, akpm, torvalds, stable; +Cc: lwn, jslaby, Greg Kroah-Hartman
diff --git a/Documentation/admin-guide/mm/damon/lru_sort.rst b/Documentation/admin-guide/mm/damon/lru_sort.rst
index 63977a89025e..5f38910c0ba7 100644
--- a/Documentation/admin-guide/mm/damon/lru_sort.rst
+++ b/Documentation/admin-guide/mm/damon/lru_sort.rst
@@ -95,8 +95,8 @@ increases and decreases the effective level of the quota aiming the LRU
Disabled by default.
-Auto-tune monitoring intervals
-------------------------------
+autotune_monitoring_intervals
+-----------------------------
If this parameter is set as ``Y``, DAMON_LRU_SORT automatically tunes DAMON's
sampling and aggregation intervals. The auto-tuning aims to capture meaningful
diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
index bfd30aae682b..360a0643a0b5 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
@@ -50,7 +50,7 @@ properties:
The 2nd cell contains the interrupt number for the interrupt type.
SPI interrupts are in the range [0-987]. PPI interrupts are in the
range [0-15]. Extended SPI interrupts are in the range [0-1023].
- Extended PPI interrupts are in the range [0-127].
+ Extended PPI interrupts are in the range [0-63].
The 3rd cell is the flags, encoded as follows:
bits[3:0] trigger type and level flags.
diff --git a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
index 7e7c55dc2440..5cebe5eb1efb 100644
--- a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
+++ b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
@@ -50,9 +50,11 @@ properties:
maxItems: 1
resets:
+ minItems: 4
maxItems: 5
reset-names:
+ minItems: 4
maxItems: 5
rockchip,txclk-tapnum:
@@ -146,6 +148,7 @@ allOf:
else:
properties:
resets:
+ minItems: 5
maxItems: 5
reset-names:
items:
diff --git a/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml b/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml
index 607b7fe8d28e..0486489114cd 100644
--- a/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml
+++ b/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml
@@ -143,8 +143,6 @@ allOf:
else:
properties:
spi-cpha: false
- required:
- - spi-cpol
unevaluatedProperties: false
diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-common.yaml b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-common.yaml
index cddbe21f99f2..0488c942092d 100644
--- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-common.yaml
+++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-common.yaml
@@ -17,11 +17,11 @@ description:
properties:
clocks:
minItems: 3
- maxItems: 5
+ maxItems: 6
clock-names:
minItems: 3
- maxItems: 5
+ maxItems: 6
num-lanes:
const: 1
diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml
index 12a01f7a5744..21dda8066014 100644
--- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml
@@ -40,7 +40,8 @@ properties:
- description: PCIe PHY clock.
- description: Additional required clock entry for imx6sx-pcie,
imx6sx-pcie-ep, imx8mq-pcie, imx8mq-pcie-ep.
- - description: PCIe reference clock.
+ - description: PCIe internal reference clock.
+ - description: PCIe additional external reference clock.
clock-names:
minItems: 3
diff --git a/Documentation/devicetree/bindings/pci/renesas,r9a08g045-pcie.yaml b/Documentation/devicetree/bindings/pci/renesas,r9a08g045-pcie.yaml
index d668782546a2..d1eb92995e2c 100644
--- a/Documentation/devicetree/bindings/pci/renesas,r9a08g045-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/renesas,r9a08g045-pcie.yaml
@@ -41,22 +41,22 @@ properties:
interrupt-names:
items:
- - description: serr
- - description: ser_cor
- - description: serr_nonfatal
- - description: serr_fatal
- - description: axi_err
- - description: inta
- - description: intb
- - description: intc
- - description: intd
- - description: msi
- - description: link_bandwidth
- - description: pm_pme
- - description: dma
- - description: pcie_evt
- - description: msg
- - description: all
+ - const: serr
+ - const: serr_cor
+ - const: serr_nonfatal
+ - const: serr_fatal
+ - const: axi_err
+ - const: inta
+ - const: intb
+ - const: intc
+ - const: intd
+ - const: msi
+ - const: link_bandwidth
+ - const: pm_pme
+ - const: dma
+ - const: pcie_evt
+ - const: msg
+ - const: all
interrupt-controller: true
@@ -67,8 +67,8 @@ properties:
clock-names:
items:
- - description: aclk
- - description: pm
+ - const: aclk
+ - const: pm
resets:
items:
@@ -82,13 +82,13 @@ properties:
reset-names:
items:
- - description: aresetn
- - description: rst_b
- - description: rst_gp_b
- - description: rst_ps_b
- - description: rst_rsm_b
- - description: rst_cfg_b
- - description: rst_load_b
+ - const: aresetn
+ - const: rst_b
+ - const: rst_gp_b
+ - const: rst_ps_b
+ - const: rst_rsm_b
+ - const: rst_cfg_b
+ - const: rst_load_b
power-domains:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada3710-xb-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/marvell,armada3710-xb-pinctrl.yaml
index 4f9013d36874..727da7fb490c 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,armada3710-xb-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada3710-xb-pinctrl.yaml
@@ -84,11 +84,12 @@ patternProperties:
properties:
groups:
- enum: [ emmc_nb, i2c1, i2c2, jtag, mii_col, onewire, pcie1,
- pcie1_clkreq, pcie1_wakeup, pmic0, pmic1, ptp, ptp_clk,
- ptp_trig, pwm0, pwm1, pwm2, pwm3, rgmii, sdio0, sdio_sb, smi,
- spi_cs1, spi_cs2, spi_cs3, spi_quad, uart1, uart2,
- usb2_drvvbus1, usb32_drvvbus0 ]
+ items:
+ enum: [ emmc_nb, i2c1, i2c2, jtag, mii_col, onewire, pcie1,
+ pcie1_clkreq, pcie1_wakeup, pmic0, pmic1, ptp, ptp_clk,
+ ptp_trig, pwm0, pwm1, pwm2, pwm3, rgmii, sdio0, sdio_sb,
+ smi, spi_cs1, spi_cs2, spi_cs3, spi_quad, uart1, uart2,
+ usb2_drvvbus1, usb32_drvvbus0 ]
function:
enum: [ drvbus, emmc, gpio, i2c, jtag, led, mii, mii_err, onewire,
diff --git a/Documentation/devicetree/bindings/regulator/fitipower,fp9931.yaml b/Documentation/devicetree/bindings/regulator/fitipower,fp9931.yaml
index c6585e3bacbe..00d66b923047 100644
--- a/Documentation/devicetree/bindings/regulator/fitipower,fp9931.yaml
+++ b/Documentation/devicetree/bindings/regulator/fitipower,fp9931.yaml
@@ -66,6 +66,7 @@ properties:
required:
- compatible
- reg
+ - vin-supply
- pg-gpios
- enable-gpios
diff --git a/Documentation/devicetree/bindings/ufs/rockchip,rk3576-ufshc.yaml b/Documentation/devicetree/bindings/ufs/rockchip,rk3576-ufshc.yaml
index c7d17cf4dc42..e738153a309c 100644
--- a/Documentation/devicetree/bindings/ufs/rockchip,rk3576-ufshc.yaml
+++ b/Documentation/devicetree/bindings/ufs/rockchip,rk3576-ufshc.yaml
@@ -41,7 +41,7 @@ properties:
maxItems: 1
resets:
- maxItems: 4
+ maxItems: 5
reset-names:
items:
@@ -49,6 +49,7 @@ properties:
- const: sys
- const: ufs
- const: grf
+ - const: mphy
reset-gpios:
maxItems: 1
@@ -98,8 +99,8 @@ examples:
interrupts = <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>;
power-domains = <&power RK3576_PD_USB>;
resets = <&cru SRST_A_UFS_BIU>, <&cru SRST_A_UFS_SYS>, <&cru SRST_A_UFS>,
- <&cru SRST_P_UFS_GRF>;
- reset-names = "biu", "sys", "ufs", "grf";
+ <&cru SRST_P_UFS_GRF>, <&cru SRST_MPHY_INIT>;
+ reset-names = "biu", "sys", "ufs", "grf", "mphy";
reset-gpios = <&gpio4 RK_PD0 GPIO_ACTIVE_LOW>;
};
};
diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst
index 7d2b897d66fa..017fb155a5bc 100644
--- a/Documentation/driver-api/driver-model/devres.rst
+++ b/Documentation/driver-api/driver-model/devres.rst
@@ -464,3 +464,7 @@ SPI
WATCHDOG
devm_watchdog_register_device()
+
+WORKQUEUE
+ devm_alloc_workqueue()
+ devm_alloc_ordered_workqueue()
diff --git a/Documentation/mm/damon/index.rst b/Documentation/mm/damon/index.rst
index 82f6c5eea49a..318f6a7bfea4 100644
--- a/Documentation/mm/damon/index.rst
+++ b/Documentation/mm/damon/index.rst
@@ -12,7 +12,7 @@ DAMON is a Linux kernel subsystem for efficient :ref:`data access monitoring
- *light-weight* (for production online usages),
- *scalable* (in terms of memory size),
- *tunable* (for flexible usages), and
- - *autoamted* (for production operation without manual tunings).
+ - *automated* (for production operation without manual tunings).
.. toctree::
:maxdepth: 2
diff --git a/Documentation/mm/hugetlbfs_reserv.rst b/Documentation/mm/hugetlbfs_reserv.rst
index 4914fbf07966..a49115db18c7 100644
--- a/Documentation/mm/hugetlbfs_reserv.rst
+++ b/Documentation/mm/hugetlbfs_reserv.rst
@@ -155,7 +155,7 @@ are enough free huge pages to accommodate the reservation. If there are,
the global reservation count resv_huge_pages is adjusted something like the
following::
- if (resv_needed <= (resv_huge_pages - free_huge_pages))
+ if (resv_needed <= (free_huge_pages - resv_huge_pages)
resv_huge_pages += resv_needed;
Note that the global lock hugetlb_lock is held when checking and adjusting
diff --git a/Documentation/netlink/specs/psp.yaml b/Documentation/netlink/specs/psp.yaml
index f3a57782d2cf..49b7563f705f 100644
--- a/Documentation/netlink/specs/psp.yaml
+++ b/Documentation/netlink/specs/psp.yaml
@@ -188,6 +188,7 @@ operations:
name: dev-set
doc: Set the configuration of a PSP device.
attribute-set: dev
+ flags: [admin-perm]
do:
request:
attributes:
@@ -207,6 +208,7 @@ operations:
name: key-rotate
doc: Rotate the device key.
attribute-set: dev
+ flags: [admin-perm]
do:
request:
attributes:
diff --git a/Documentation/userspace-api/rseq.rst b/Documentation/userspace-api/rseq.rst
index 3cd27a3c7c7e..8549a6c61531 100644
--- a/Documentation/userspace-api/rseq.rst
+++ b/Documentation/userspace-api/rseq.rst
@@ -24,6 +24,97 @@ Quick access to CPU number, node ID
Allows to implement per CPU data efficiently. Documentation is in code and
selftests. :(
+Optimized RSEQ V2
+-----------------
+
+On architectures which utilize the generic entry code and generic TIF bits
+the kernel supports runtime optimizations for RSEQ, which also enable
+enhanced features like scheduler time slice extensions.
+
+To enable them a task has to register the RSEQ region with at least the
+length advertised by getauxval(AT_RSEQ_FEATURE_SIZE).
+
+If existing binaries register with RSEQ_ORIG_SIZE (32 bytes), the kernel
+keeps the legacy low performance mode enabled to fulfil the expectations
+of existing users regarding the original RSEQ implementation behaviour.
+
+The following table documents the ABI and behavioral guarantees of the
+legacy and the optimized V2 mode.
+
+.. list-table:: RSEQ modes
+ :header-rows: 1
+
+ * - Nr
+ - What
+
+ - Legacy
+ - Optimized V2
+
+ * - 1
+ - The cpu_id_start, cpu_id, node_id and mm_cid fields (User mode read
+ only)
+ .. Legacy
+ - Updated by the kernel unconditionally after each context switch and
+ before signal delivery
+ .. Optimized V2
+ - Updated by the kernel if and only if they change, i.e. if the task
+ is migrated or mm_cid changes
+
+ * - 2
+ - The rseq_cs critical section field
+ .. Legacy
+ - Evaluated and handled unconditionally after each context switch and
+ before signal delivery
+ .. Optimized V2
+ - Evaluated and handled conditionally only when user space was
+ interrupted and was scheduled out or before delivering a signal in
+ the interrupted context.
+
+ * - 3
+ - Read only fields
+ .. Legacy
+ - No strict enforcement except in debug mode
+ .. Optimized V2
+ - Strict enforcement
+
+ * - 4
+ - membarrier(...RSEQ)
+ .. Legacy
+ - All running threads of the process are interrupted and the ID fields
+ are rewritten and eventually active critical sections are aborted
+ before they return to user space. All threads which are scheduled
+ out whether voluntary or not are covered by #1/#2 above.
+ .. Optimized V2
+ - All running threads of the process are interrupted and eventually
+ active critical sections are aborted before these threads return to
+ user space. The ID fields are only updated if changed as a
+ consequence of the interrupt. All threads which are scheduled out
+ whether voluntary or not are covered by #1/#2 above.
+
+ * - 5
+ - Time slice extensions
+ .. Legacy
+ - Not supported
+ .. Optimized V2
+ - Supported
+
+The legacy mode is obviously less performant as it does unconditional
+updates and critical section checks even if not strictly required by the
+ABI contract. That can't be changed anymore as some users depend on that
+observed behavior, which in turn enables them to violate the ABI and
+overwrite the cpu_id_start field for their own purposes. This is obviously
+discouraged as it renders RSEQ incompatible with the intended usage and
+breaks the expectation of other libraries in the same application.
+
+The ABI compliant optimized v2 mode, which respects the read only fields,
+does not require unconditional updates and therefore is way more
+performant. The kernel validates the read only fields for compliance. If
+user space modifies them, the process is killed. Compliant usage allows
+multiple libraries in the same application to benefit from the RSEQ
+functionality without disturbing each other. The ABI compliant optimized v2
+mode also enables extended RSEQ features like time slice extensions.
+
+
Scheduler time slice extensions
-------------------------------
@@ -37,7 +128,8 @@ The prerequisites for this functionality are:
* Enabled at boot time (default is enabled)
- * A rseq userspace pointer has been registered for the thread
+ * A rseq userspace pointer has been registered for the thread in
+ optimized V2 mode
The thread has to enable the functionality via prctl(2)::
diff --git a/Makefile b/Makefile
index 9da9c1f3b238..a95f0b3d26bf 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
VERSION = 7
PATCHLEVEL = 0
-SUBLEVEL = 9
+SUBLEVEL = 10
EXTRAVERSION =
NAME = Baby Opossum Posse
@@ -658,6 +658,8 @@ export RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o \
# Basic helpers built in scripts/basic/
PHONY += scripts_basic
+scripts_basic: KBUILD_HOSTCFLAGS := $(KBUILD_HOSTCFLAGS)
+scripts_basic: KBUILD_HOSTLDFLAGS := $(KBUILD_HOSTLDFLAGS)
scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic
diff --git a/arch/arc/net/bpf_jit_arcv2.c b/arch/arc/net/bpf_jit_arcv2.c
index 6d989b6d88c6..7ee50aeae5a4 100644
--- a/arch/arc/net/bpf_jit_arcv2.c
+++ b/arch/arc/net/bpf_jit_arcv2.c
@@ -2427,7 +2427,7 @@ u8 arc_prologue(u8 *buf, u32 usage, u16 frame_size)
#ifdef ARC_BPF_JIT_DEBUG
if ((usage & BIT(ARC_R_FP)) && frame_size == 0) {
- pr_err("FP is being saved while there is no frame.");
+ pr_err("FP is being saved while there is no frame.\n");
BUG();
}
#endif
@@ -2454,7 +2454,7 @@ u8 arc_epilogue(u8 *buf, u32 usage, u16 frame_size)
#ifdef ARC_BPF_JIT_DEBUG
if ((usage & BIT(ARC_R_FP)) && frame_size == 0) {
- pr_err("FP is being saved while there is no frame.");
+ pr_err("FP is being saved while there is no frame.\n");
BUG();
}
#endif
@@ -2868,7 +2868,7 @@ u8 gen_jmp_64(u8 *buf, u8 rd, u8 rs, u8 cond, u32 curr_off, u32 targ_off)
break;
default:
#ifdef ARC_BPF_JIT_DEBUG
- pr_err("64-bit jump condition is not known.");
+ pr_err("64-bit jump condition is not known.\n");
BUG();
#endif
}
@@ -2948,7 +2948,7 @@ u8 gen_jmp_32(u8 *buf, u8 rd, u8 rs, u8 cond, u32 curr_off, u32 targ_off)
*/
if (cond >= ARC_CC_LAST) {
#ifdef ARC_BPF_JIT_DEBUG
- pr_err("32-bit jump condition is not known.");
+ pr_err("32-bit jump condition is not known.\n");
BUG();
#endif
return 0;
diff --git a/arch/arm/boot/dts/broadcom/bcm-ns.dtsi b/arch/arm/boot/dts/broadcom/bcm-ns.dtsi
index d0d5f7e52a91..46b650abdb90 100644
--- a/arch/arm/boot/dts/broadcom/bcm-ns.dtsi
+++ b/arch/arm/boot/dts/broadcom/bcm-ns.dtsi
@@ -479,7 +479,7 @@ thermal: thermal@2c0 {
};
nand_controller: nand-controller@18028000 {
- compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1", "brcm,brcmnand";
+ compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1";
reg = <0x18028000 0x600>, <0x1811a408 0x600>, <0x18028f00 0x20>;
reg-names = "nand", "iproc-idm", "iproc-ext";
interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/mediatek/mt7623.dtsi b/arch/arm/boot/dts/mediatek/mt7623.dtsi
index 4b1685b93989..71ac2b94c6ba 100644
--- a/arch/arm/boot/dts/mediatek/mt7623.dtsi
+++ b/arch/arm/boot/dts/mediatek/mt7623.dtsi
@@ -328,7 +328,7 @@ sysirq: interrupt-controller@10200100 {
efuse: efuse@10206000 {
compatible = "mediatek,mt7623-efuse",
- "mediatek,mt8173-efuse";
+ "mediatek,efuse";
reg = <0 0x10206000 0 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi
index c7e923584878..9f0e65526d5f 100644
--- a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi
+++ b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi
@@ -106,7 +106,7 @@ uart8250@3,200000 {
compatible = "ns8250";
clocks = <&clk14745600>;
fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>;
- interrupts = <&gpio2 23 IRQ_TYPE_LEVEL_LOW>;
+ interrupts-extended = <&gpio2 23 IRQ_TYPE_LEVEL_LOW>;
reg = <3 0x200000 0x1000>;
reg-shift = <1>;
reg-io-width = <1>;
@@ -119,7 +119,7 @@ uart8250@3,400000 {
compatible = "ns8250";
clocks = <&clk14745600>;
fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>;
- interrupts = <&gpio2 22 IRQ_TYPE_LEVEL_LOW>;
+ interrupts-extended = <&gpio2 22 IRQ_TYPE_LEVEL_LOW>;
reg = <3 0x400000 0x1000>;
reg-shift = <1>;
reg-io-width = <1>;
@@ -132,7 +132,7 @@ uart8250@3,800000 {
compatible = "ns8250";
clocks = <&clk14745600>;
fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>;
- interrupts = <&gpio2 27 IRQ_TYPE_LEVEL_LOW>;
+ interrupts-extended = <&gpio2 27 IRQ_TYPE_LEVEL_LOW>;
reg = <3 0x800000 0x1000>;
reg-shift = <1>;
reg-io-width = <1>;
@@ -145,7 +145,7 @@ uart8250@3,1000000 {
compatible = "ns8250";
clocks = <&clk14745600>;
fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>;
- interrupts = <&gpio2 30 IRQ_TYPE_LEVEL_LOW>;
+ interrupts-extended = <&gpio2 30 IRQ_TYPE_LEVEL_LOW>;
reg = <3 0x1000000 0x1000>;
reg-shift = <1>;
reg-io-width = <1>;
diff --git a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts
index d78793601306..c71f80298330 100644
--- a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts
+++ b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts
@@ -76,7 +76,7 @@ ads7846@0 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_touch>;
reg = <0>;
- interrupts = <&gpio4 25 IRQ_TYPE_LEVEL_LOW>;
+ interrupts-extended = <&gpio4 25 IRQ_TYPE_LEVEL_LOW>;
spi-cpol;
spi-max-frequency = <1500000>;
ti,keep-vref-on;
diff --git a/arch/arm/mach-omap1/clock_data.c b/arch/arm/mach-omap1/clock_data.c
index c58d200e4816..5203b047deac 100644
--- a/arch/arm/mach-omap1/clock_data.c
+++ b/arch/arm/mach-omap1/clock_data.c
@@ -700,8 +700,8 @@ int __init omap1_clk_init(void)
/* Make sure UART clocks are enabled early */
if (cpu_is_omap16xx())
omap_writel(omap_readl(MOD_CONF_CTRL_0) |
- CONF_MOD_UART1_CLK_MODE_R |
- CONF_MOD_UART3_CLK_MODE_R, MOD_CONF_CTRL_0);
+ (1 << CONF_MOD_UART1_CLK_MODE_R) |
+ (1 << CONF_MOD_UART3_CLK_MODE_R), MOD_CONF_CTRL_0);
#endif
/* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index deeb8f292454..a900aa973885 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -1852,6 +1852,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
{
u64 val = (u32)imm | (u64)insn[1].imm << 32;
+ if (insn->src_reg == BPF_PSEUDO_FUNC)
+ goto notyet;
+
emit_a32_mov_i64(dst, val, ctx);
return 1;
@@ -2055,6 +2058,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
const s8 *r5 = bpf2a32[BPF_REG_5];
const u32 func = (u32)__bpf_call_base + (u32)imm;
+ if (insn->src_reg == BPF_PSEUDO_CALL)
+ goto notyet;
+
emit_a32_mov_r64(true, r0, r1, ctx);
emit_a32_mov_r64(true, r1, r2, ctx);
emit_push_r64(r5, ctx);
diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
index cc72491eaf6f..f1f53fd98ae2 100644
--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
@@ -72,6 +72,12 @@ cpu0: cpu@0 {
compatible = "arm,cortex-a53";
reg = <0x0 0x0>;
enable-method = "psci";
+ d-cache-line-size = <32>;
+ d-cache-size = <0x8000>;
+ d-cache-sets = <32>;
+ i-cache-line-size = <32>;
+ i-cache-size = <0x8000>;
+ i-cache-sets = <32>;
next-level-cache = <&l2>;
clocks = <&scpi_dvfs 0>;
dynamic-power-coefficient = <140>;
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
index 7dffeb5931c9..701de57ff0f3 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
@@ -84,7 +84,8 @@ external_phy: ethernet-phy@0 {
reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
interrupt-parent = <&gpio_intc>;
- interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
+ /* MAC_INTR on GPIOZ_15 */
+ interrupts = <25 IRQ_TYPE_LEVEL_LOW>;
eee-broken-1000t;
};
};
diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
index af74e77efabc..479982948ee5 100644
--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
@@ -750,9 +750,10 @@ i2c0: i2c@2000000 {
clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
QORIQ_CLK_PLL_DIV(16)>;
pinctrl-names = "default", "gpio";
- pinctrl-0 = <&i2c0_scl>;
- pinctrl-1 = <&i2c0_scl_gpio>;
+ pinctrl-0 = <&i2c0_pins>;
+ pinctrl-1 = <&gpio0_3_2_pins>;
scl-gpios = <&gpio0 3 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio0 2 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "disabled";
};
@@ -766,9 +767,10 @@ i2c1: i2c@2010000 {
clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
QORIQ_CLK_PLL_DIV(16)>;
pinctrl-names = "default", "gpio";
- pinctrl-0 = <&i2c1_scl>;
- pinctrl-1 = <&i2c1_scl_gpio>;
+ pinctrl-0 = <&i2c1_pins>;
+ pinctrl-1 = <&gpio0_31_30_pins>;
scl-gpios = <&gpio0 31 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio0 30 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "disabled";
};
@@ -782,9 +784,10 @@ i2c2: i2c@2020000 {
clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
QORIQ_CLK_PLL_DIV(16)>;
pinctrl-names = "default", "gpio";
- pinctrl-0 = <&i2c2_scl>;
- pinctrl-1 = <&i2c2_scl_gpio>;
+ pinctrl-0 = <&i2c2_pins>;
+ pinctrl-1 = <&gpio0_29_28_pins>;
scl-gpios = <&gpio0 29 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio0 28 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "disabled";
};
@@ -798,9 +801,10 @@ i2c3: i2c@2030000 {
clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
QORIQ_CLK_PLL_DIV(16)>;
pinctrl-names = "default", "gpio";
- pinctrl-0 = <&i2c3_scl>;
- pinctrl-1 = <&i2c3_scl_gpio>;
+ pinctrl-0 = <&i2c3_pins>;
+ pinctrl-1 = <&gpio0_27_26_pins>;
scl-gpios = <&gpio0 27 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio0 26 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "disabled";
};
@@ -814,9 +818,10 @@ i2c4: i2c@2040000 {
clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
QORIQ_CLK_PLL_DIV(16)>;
pinctrl-names = "default", "gpio";
- pinctrl-0 = <&i2c4_scl>;
- pinctrl-1 = <&i2c4_scl_gpio>;
+ pinctrl-0 = <&i2c4_pins>;
+ pinctrl-1 = <&gpio0_25_24_pins>;
scl-gpios = <&gpio0 25 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio0 24 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "disabled";
};
@@ -830,9 +835,10 @@ i2c5: i2c@2050000 {
clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
QORIQ_CLK_PLL_DIV(16)>;
pinctrl-names = "default", "gpio";
- pinctrl-0 = <&i2c5_scl>;
- pinctrl-1 = <&i2c5_scl_gpio>;
+ pinctrl-0 = <&i2c5_pins>;
+ pinctrl-1 = <&gpio0_23_22_pins>;
scl-gpios = <&gpio0 23 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio0 22 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "disabled";
};
@@ -846,9 +852,10 @@ i2c6: i2c@2060000 {
clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
QORIQ_CLK_PLL_DIV(16)>;
pinctrl-names = "default", "gpio";
- pinctrl-0 = <&i2c6_scl>;
- pinctrl-1 = <&i2c6_scl_gpio>;
+ pinctrl-0 = <&i2c6_i2c7_pins>;
+ pinctrl-1 = <&gpio1_18_15_pins>;
scl-gpios = <&gpio1 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio1 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "disabled";
};
@@ -862,9 +869,10 @@ i2c7: i2c@2070000 {
clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
QORIQ_CLK_PLL_DIV(16)>;
pinctrl-names = "default", "gpio";
- pinctrl-0 = <&i2c7_scl>;
- pinctrl-1 = <&i2c7_scl_gpio>;
+ pinctrl-0 = <&i2c6_i2c7_pins>;
+ pinctrl-1 = <&gpio1_18_15_pins>;
scl-gpios = <&gpio1 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio1 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
status = "disabled";
};
@@ -1713,92 +1721,159 @@ pinmux_i2crv: pinmux@70010012c {
pinctrl-single,register-width = <32>;
pinctrl-single,function-mask = <0x7>;
- i2c1_scl: i2c1-scl-pins {
- pinctrl-single,bits = <0x0 0 0x7>;
+ /* RCWSR12 */
+ i2c1_pins: iic2-i2c-pins {
+ pinctrl-single,bits = <0x0 0x0 0x7>;
};
- i2c1_scl_gpio: i2c1-scl-gpio-pins {
+ gpio0_31_30_pins: iic2-gpio-pins {
pinctrl-single,bits = <0x0 0x1 0x7>;
};
+ ftm0_ch10_pins: iic2-ftm-pins {
+ pinctrl-single,bits = <0x0 0x2 0x7>;
+ };
+
esdhc0_cd_wp_pins: iic2-sdhc-pins {
pinctrl-single,bits = <0x0 0x6 0x7>;
};
- i2c2_scl: i2c2-scl-pins {
- pinctrl-single,bits = <0x0 0 (0x7 << 3)>;
+ i2c2_pins: iic3-i2c-pins {
+ pinctrl-single,bits = <0x0 0x0 (0x7 << 3)>;
};
- i2c2_scl_gpio: i2c2-scl-gpio-pins {
+ gpio0_29_28_pins: iic3-gpio-pins {
pinctrl-single,bits = <0x0 (0x1 << 3) (0x7 << 3)>;
};
- i2c3_scl: i2c3-scl-pins {
- pinctrl-single,bits = <0x0 0 (0x7 << 6)>;
+ can0_pins: iic3-can-pins {
+ pinctrl-single,bits = <0x0 (0x2 << 3) (0x7 << 3)>;
+ };
+
+ event65_pins: iic3-event-pins {
+ pinctrl-single,bits = <0x0 (0x6 << 3) (0x7 << 3)>;
+ };
+
+ i2c3_pins: iic4-i2c-pins {
+ pinctrl-single,bits = <0x0 0x0 (0x7 << 6)>;
};
- i2c3_scl_gpio: i2c3-scl-gpio-pins {
+ gpio0_27_26_pins: iic4-gpio-pins {
pinctrl-single,bits = <0x0 (0x1 << 6) (0x7 << 6)>;
};
- i2c4_scl: i2c4-scl-pins {
- pinctrl-single,bits = <0x0 0 (0x7 << 9)>;
+ can1_pins: iic4-can-pins {
+ pinctrl-single,bits = <0x0 (0x2 << 6) (0x7 << 6)>;
+ };
+
+ event87_pins: iic4-event-pins {
+ pinctrl-single,bits = <0x0 (0x6 << 6) (0x7 << 6)>;
+ };
+
+ i2c4_pins: iic5-i2c-pins {
+ pinctrl-single,bits = <0x0 0x0 (0x7 << 9)>;
};
- i2c4_scl_gpio: i2c4-scl-gpio-pins {
+ gpio0_25_24_pins: iic5-gpio-pins {
pinctrl-single,bits = <0x0 (0x1 << 9) (0x7 << 9)>;
};
- i2c5_scl: i2c5-scl-pins {
- pinctrl-single,bits = <0x0 0 (0x7 << 12)>;
+ esdhc0_clksync_pins: iic5-sdhc-clk-pins {
+ pinctrl-single,bits = <0x0 (0x2 << 9) (0x7 << 9)>;
};
- i2c5_scl_gpio: i2c5-scl-gpio-pins {
+ dspi2_miso_mosi_pins: iic5-spi3-pins {
+ pinctrl-single,bits = <0x3 (0x2 << 9) (0x7 << 9)>;
+ };
+
+ i2c5_pins: iic6-i2c-pins {
+ pinctrl-single,bits = <0x0 0x0 (0x7 << 12)>;
+ };
+
+ gpio0_23_22_pins: iic6-gpio-pins {
pinctrl-single,bits = <0x0 (0x1 << 12) (0x7 << 12)>;
};
+ esdhc1_clksync_pins: iic6-sdhc-clk-pins {
+ pinctrl-single,bits = <0x0 (0x2 << 12) (0x7 << 12)>;
+ };
+
fspi_data74_pins: xspi1-data74-pins {
pinctrl-single,bits = <0x0 0x0 (0x7 << 15)>;
};
+ gpio1_31_28_pins: xspi1-data74-gpio-pins {
+ pinctrl-single,bits = <0x0 0x1 (0x7 << 15)>;
+ };
+
fspi_data30_pins: xspi1-data30-pins {
pinctrl-single,bits = <0x0 0x0 (0x7 << 18)>;
};
+ gpio1_27_24_pins: xspi1-data30-gpio-pins {
+ pinctrl-single,bits = <0x0 0x1 (0x7 << 18)>;
+ };
+
fspi_dqs_sck_cs10_pins: xspi1-base-pins {
pinctrl-single,bits = <0x0 0x0 (0x7 << 21)>;
};
+ gpio1_23_20_pins: xspi1-base-gpio-pins {
+ pinctrl-single,bits = <0x0 0x1 (0x7 << 21)>;
+ };
+
esdhc0_cmd_data30_clk_vsel_pins: sdhc1-base-sdhc-vsel-pins {
pinctrl-single,bits = <0x0 0x0 (0x7 << 24)>;
};
+ gpio0_21_15_pins: sdhc1-base-gpio-pins {
+ pinctrl-single,bits = <0x0 (0x1 << 24) (0x7 << 24)>;
+ };
+
+ dspi0_pins: sdhc1-base-spi1-pins {
+ pinctrl-single,bits = <0x0 (0x2 << 24) (0x7 << 24)>;
+ };
+
+ esdhc0_cmd_data30_clk_dspi2_cs0_pins: sdhc1-base-sdhc-spi3-pins {
+ pinctrl-single,bits = <0x0 (0x3 << 24) (0x7 << 24)>;
+ };
+
+ esdhc0_cmd_data30_clk_data4_pins: sdhc1-base-sdhc-data4-pins {
+ pinctrl-single,bits = <0x0 (0x4 << 24) (0x7 << 24)>;
+ };
+
+ esdhc0_dir_pins: sdhc1-dir-pins {
+ pinctrl-single,bits = <0x0 0x0 (0x7 << 27)>;
+ };
+
gpio0_14_12_pins: sdhc1-dir-gpio-pins {
pinctrl-single,bits = <0x0 (0x1 << 27) (0x7 << 27)>;
};
- i2c6_scl: i2c6-scl-pins {
- pinctrl-single,bits = <0x4 0x2 0x7>;
+ dspi2_cs31_pins: sdhc1-dir-spi3-pins {
+ pinctrl-single,bits = <0x0 (0x3 << 27) (0x7 << 27)>;
};
- i2c6_scl_gpio: i2c6-scl-gpio-pins {
- pinctrl-single,bits = <0x4 0x1 0x7>;
+ esdhc0_data75_pins: sdhc1-dir-sdhc-pins {
+ pinctrl-single,bits = <0x0 (0x4 << 27) (0x7 << 27)>;
};
- i2c7_scl: i2c7-scl-pins {
- pinctrl-single,bits = <0x4 0x2 0x7>;
+ /* RCWSR13 */
+ gpio1_18_15_pins: iic8-iic7-gpio-pins {
+ pinctrl-single,bits = <0x4 0x1 0x7>;
};
- i2c7_scl_gpio: i2c7-scl-gpio-pins {
- pinctrl-single,bits = <0x4 0x1 0x7>;
+ i2c6_i2c7_pins: iic8-iic7-i2c-pins {
+ pinctrl-single,bits = <0x4 0x2 0x7>;
};
- i2c0_scl: i2c0-scl-pins {
- pinctrl-single,bits = <0x8 0 (0x7 << 10)>;
+ /* RCWSR14 */
+ i2c0_pins: iic1-i2c-pins {
+ pinctrl-single,bits = <0x8 0x0 (0x1 << 10)>;
};
- i2c0_scl_gpio: i2c0-scl-gpio-pins {
- pinctrl-single,bits = <0x8 (0x1 << 10) (0x7 << 10)>;
+ gpio0_3_2_pins: iic1-gpio-pins {
+ pinctrl-single,bits = <0x8 (0x1 << 10) (0x1 << 10)>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi
index 7022de46b8bf..abb131d247c3 100644
--- a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi
@@ -21,6 +21,7 @@ led-1 {
color = <LED_COLOR_ID_GREEN>;
default-state = "off";
function = LED_FUNCTION_STATUS;
+ function-enumerator = <1>;
gpios = <&lsio_gpio5 27 GPIO_ACTIVE_HIGH>;
};
@@ -29,6 +30,7 @@ led-2 {
color = <LED_COLOR_ID_RED>;
default-state = "off";
function = LED_FUNCTION_STATUS;
+ function-enumerator = <1>;
gpios = <&lsio_gpio5 29 GPIO_ACTIVE_HIGH>;
};
@@ -37,6 +39,7 @@ led-3 {
color = <LED_COLOR_ID_GREEN>;
default-state = "off";
function = LED_FUNCTION_STATUS;
+ function-enumerator = <2>;
gpios = <&lsio_gpio5 20 GPIO_ACTIVE_HIGH>;
};
@@ -45,6 +48,7 @@ led-4 {
color = <LED_COLOR_ID_RED>;
default-state = "off";
function = LED_FUNCTION_STATUS;
+ function-enumerator = <2>;
gpios = <&lsio_gpio5 21 GPIO_ACTIVE_HIGH>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi
index 12732ed7f811..a0b452b92b3e 100644
--- a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi
@@ -21,6 +21,7 @@ led-1 {
color = <LED_COLOR_ID_GREEN>;
default-state = "off";
function = LED_FUNCTION_STATUS;
+ function-enumerator = <1>;
gpios = <&lsio_gpio5 27 GPIO_ACTIVE_HIGH>;
};
@@ -29,6 +30,7 @@ led-2 {
color = <LED_COLOR_ID_RED>;
default-state = "off";
function = LED_FUNCTION_STATUS;
+ function-enumerator = <1>;
gpios = <&lsio_gpio5 29 GPIO_ACTIVE_HIGH>;
};
@@ -37,6 +39,7 @@ led-3 {
color = <LED_COLOR_ID_GREEN>;
default-state = "off";
function = LED_FUNCTION_STATUS;
+ function-enumerator = <2>;
gpios = <&lsio_gpio5 20 GPIO_ACTIVE_HIGH>;
};
@@ -45,6 +48,7 @@ led-4 {
color = <LED_COLOR_ID_RED>;
default-state = "off";
function = LED_FUNCTION_STATUS;
+ function-enumerator = <2>;
gpios = <&lsio_gpio5 21 GPIO_ACTIVE_HIGH>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts b/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts
index 5c68d33e19f2..bc62ae5ca812 100644
--- a/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts
@@ -259,33 +259,37 @@ sound-wm8960-1 {
};
sound-wm8960-2 {
- compatible = "fsl,imx-audio-wm8960";
- model = "wm8960-audio-2";
- audio-cpu = <&sai2>;
- audio-codec = <&wm8960_2>;
- audio-routing = "Headphone Jack", "HP_L",
- "Headphone Jack", "HP_R",
- "Ext Spk", "SPK_LP",
- "Ext Spk", "SPK_LN",
- "Ext Spk", "SPK_RP",
- "Ext Spk", "SPK_RN",
- "LINPUT1", "Mic Jack",
- "Mic Jack", "MICB";
+ compatible = "audio-graph-card2";
+ label = "wm8960-audio-2";
+ links = <&sai2_port2>;
+ routing = "Headphones", "HP_L",
+ "Headphones", "HP_R",
+ "Ext Spk", "SPK_LP",
+ "Ext Spk", "SPK_LN",
+ "Ext Spk", "SPK_RP",
+ "Ext Spk", "SPK_RN",
+ "LINPUT1", "Mic Jack",
+ "Mic Jack", "MICB";
+ widgets = "Headphone", "Headphones",
+ "Speaker", "Ext Spk",
+ "Microphone", "Mic Jack";
};
sound-wm8960-3 {
- compatible = "fsl,imx-audio-wm8960";
- model = "wm8960-audio-3";
- audio-cpu = <&sai3>;
- audio-codec = <&wm8960_3>;
- audio-routing = "Headphone Jack", "HP_L",
- "Headphone Jack", "HP_R",
- "Ext Spk", "SPK_LP",
- "Ext Spk", "SPK_LN",
- "Ext Spk", "SPK_RP",
- "Ext Spk", "SPK_RN",
- "LINPUT1", "Mic Jack",
- "Mic Jack", "MICB";
+ compatible = "audio-graph-card2";
+ label = "wm8960-audio-3";
+ links = <&sai3_port2>;
+ routing = "Headphones", "HP_L",
+ "Headphones", "HP_R",
+ "Ext Spk", "SPK_LP",
+ "Ext Spk", "SPK_LN",
+ "Ext Spk", "SPK_RP",
+ "Ext Spk", "SPK_RN",
+ "LINPUT1", "Mic Jack",
+ "Mic Jack", "MICB";
+ widgets = "Headphone", "Headphones",
+ "Speaker", "Ext Spk",
+ "Microphone", "Mic Jack";
};
};
@@ -481,6 +485,16 @@ wm8960_2: audio-codec@1a {
DCVDD-supply = <®_audio_1v8>;
SPKVDD1-supply = <®_audio_5v>;
SPKVDD2-supply = <®_audio_5v>;
+
+ port {
+ capture-only;
+
+ wm8960_2_ep: endpoint {
+ bitclock-master;
+ frame-master;
+ remote-endpoint = <&sai2_endpoint2>;
+ };
+ };
};
};
@@ -510,6 +524,16 @@ wm8960_3: audio-codec@1a {
DCVDD-supply = <®_audio_1v8>;
SPKVDD1-supply = <®_audio_5v>;
SPKVDD2-supply = <®_audio_5v>;
+
+ port {
+ capture-only;
+
+ wm8960_3_ep: endpoint {
+ bitclock-master;
+ frame-master;
+ remote-endpoint = <&sai3_endpoint2>;
+ };
+ };
};
};
@@ -700,6 +724,27 @@ &sai2 {
pinctrl-0 = <&pinctrl_sai2>;
fsl,sai-asynchronous;
status = "okay";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sai2_port1: port@1 {
+ reg = <1>;
+ endpoint { /* not used */ };
+ };
+
+ sai2_port2: port@2 {
+ reg = <2>;
+ capture-only;
+
+ sai2_endpoint2: endpoint {
+ dai-format = "i2s";
+ remote-endpoint = <&wm8960_2_ep>;
+ system-clock-direction-out;
+ };
+ };
+ };
};
&sai3 {
@@ -712,6 +757,27 @@ &sai3 {
pinctrl-0 = <&pinctrl_sai3>;
fsl,sai-asynchronous;
status = "okay";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sai3_port1: port@1 {
+ reg = <1>;
+ endpoint { /* not used */ };
+ };
+
+ sai3_port2: port@2 {
+ reg = <2>;
+ capture-only;
+
+ sai3_endpoint2: endpoint {
+ dai-format = "i2s";
+ remote-endpoint = <&wm8960_3_ep>;
+ system-clock-direction-out;
+ };
+ };
+ };
};
&thermal_zones {
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi
index 67d22d3768aa..507d1824d99d 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi
@@ -60,7 +60,7 @@ pmic@25 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pmic>;
interrupt-parent = <&gpio1>;
- interrupts = <3 IRQ_TYPE_EDGE_RISING>;
+ interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
regulators {
buck1: BUCK1 {
@@ -194,7 +194,7 @@ MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA 0x400001c3
pinctrl_pmic: emtop-pmic-grp {
fsl,pins = <
- MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x41
+ MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x141
>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi
index 29b298af0d73..1b5ba3c47164 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi
@@ -292,7 +292,7 @@ pinctrl_i2c1_gpio: i2c1gpiogrp {
};
pinctrl_pmic: pmicgrp {
- fsl,pins = <MX8MM_IOMUXC_GPIO1_IO08_GPIO1_IO8 0x94>;
+ fsl,pins = <MX8MM_IOMUXC_GPIO1_IO08_GPIO1_IO8 0x1d4>;
};
pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi
index 31a3ca137e63..48a687926aa1 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi
@@ -283,7 +283,7 @@ pinctrl_i2c1_gpio: i2c1gpiogrp {
};
pinctrl_pmic: pmicgrp {
- fsl,pins = <MX8MN_IOMUXC_GPIO1_IO08_GPIO1_IO8 0x84>;
+ fsl,pins = <MX8MN_IOMUXC_GPIO1_IO08_GPIO1_IO8 0x1c4>;
};
pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-aristainetos3a-som-v1.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-aristainetos3a-som-v1.dtsi
index f654d866e58c..e7666e54310b 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-aristainetos3a-som-v1.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-aristainetos3a-som-v1.dtsi
@@ -903,7 +903,7 @@ MX8MP_IOMUXC_SAI1_MCLK__GPIO4_IO20 0x41
pinctrl_pmic: aristainetos3-pmic-grp {
fsl,pins = <
- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41
+ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0
>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts b/arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts
index 8290f187b79f..7bc213499f09 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts
@@ -68,7 +68,7 @@ vmmc: regulator-mmc {
regulator-name = "vmmc";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
- gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+ gpio = <&gpio2 19 GPIO_ACTIVE_LOW>;
startup-delay-us = <250>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts
index 7e46537a22a0..cb28cf1cdd23 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts
@@ -1001,7 +1001,7 @@ MX8MP_IOMUXC_SAI3_RXFS__AUDIOMIX_PDM_BIT_STREAM00 0x0
pinctrl_pmic: pmic-grp {
fsl,pins = <
/* PMIC_nINT */
- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x40000090
+ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0
>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts
index 9422beee30b2..201cf7f5eb0e 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts
@@ -440,7 +440,7 @@ MX8MP_IOMUXC_SAI5_RXC__I2C6_SDA 0x400001c3
pinctrl_pmic: pmicirqgrp {
fsl,pins = <
- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41
+ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0
>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts
index 04619a722906..1471ff361b54 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts
@@ -499,7 +499,7 @@ MX8MP_IOMUXC_SAI1_RXD1__GPIO4_IO03 0x140
pinctrl_pmic: pmicgrp {
fsl,pins = <
- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41
+ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0
>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi
index 91094c227744..b31e8fe95ca7 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi
@@ -241,7 +241,7 @@ MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA 0x400001c3
pinctrl_pmic: pmicgrp {
fsl,pins = <
- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41
+ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0
>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi
index f8303b7e2bd2..0a6a60670f76 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi
@@ -989,7 +989,7 @@ MX8MP_IOMUXC_SAI5_RXC__GPIO3_IO20 0x22
pinctrl_pmic: dhcom-pmic-grp {
fsl,pins = <
/* PMIC_nINT */
- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x40000090
+ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0
>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-edm-g.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-edm-g.dtsi
index 3f1e0837f349..91b87a7248dd 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-edm-g.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-edm-g.dtsi
@@ -563,7 +563,7 @@ MX8MP_IOMUXC_GPIO1_IO01__GPIO1_IO01 0x41 /* PCIE RST */
pinctrl_pmic: pmicirqgrp {
fsl,pins = <
- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41
+ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0
>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
index b256be710ea1..f981504f019d 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
@@ -595,7 +595,8 @@ ov5640_mipi_0_ep: endpoint {
hdmi@3d {
compatible = "adi,adv7535";
- reg = <0x3d>;
+ reg = <0x3d>, <0x3f>, <0x3b>, <0x38>;
+ reg-names = "main", "edid", "cec", "packet";
interrupt-parent = <&gpio1>;
interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
adi,dsi-lanes = <4>;
@@ -1064,7 +1065,7 @@ MX8MP_IOMUXC_SD1_DATA5__GPIO2_IO07 0x40
pinctrl_pcie0_reg: pcie0reggrp {
fsl,pins = <
- MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 0x40
+ MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 0x140
>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi
index fa7cb9759d01..0b4e5f300eb1 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi
@@ -73,7 +73,7 @@ vmmc: regulator-mmc {
regulator-name = "vmmc";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
- gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+ gpio = <&gpio2 19 GPIO_ACTIVE_LOW>;
startup-delay-us = <250>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi
index 46916ddc0533..0e5f4607c7c1 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi
@@ -41,7 +41,7 @@ port@0 {
reg = <0>;
adv7535_from_dsim: endpoint {
- remote-endpoint = <&dsim_to_adv7535>;
+ remote-endpoint = <&mipi_dsi_out>;
};
};
@@ -71,11 +71,8 @@ &lcdif1 {
&mipi_dsi {
samsung,esc-clock-frequency = <10000000>;
status = "okay";
+};
- port@1 {
- dsim_to_adv7535: endpoint {
- remote-endpoint = <&adv7535_from_dsim>;
- attach-bridge;
- };
- };
+&mipi_dsi_out {
+ remote-endpoint = <&adv7535_from_dsim>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi
index a6319824ea2e..69558ffefa9a 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi
@@ -132,7 +132,7 @@ MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA 0x400001c3
pinctrl_pmic: pmicgrp {
fsl,pins = <
- MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01 0x41
+ MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01 0x1c0
>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-kontron-dl.dtso b/arch/arm64/boot/dts/freescale/imx8mp-kontron-dl.dtso
index a3cba41d2b53..7131e9a499ae 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-kontron-dl.dtso
+++ b/arch/arm64/boot/dts/freescale/imx8mp-kontron-dl.dtso
@@ -77,6 +77,8 @@ &i2c1 {
touchscreen@5d {
compatible = "goodix,gt928";
reg = <0x5d>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_touch>;
interrupt-parent = <&gpio1>;
interrupts = <6 8>;
irq-gpios = <&gpio1 6 0>;
@@ -98,6 +100,16 @@ &lvds_bridge {
status = "okay";
};
+/* redefine to remove touch controller GPIOs */
+&pinctrl_gpio1 {
+ fsl,pins = <
+ MX8MP_IOMUXC_GPIO1_IO00__GPIO1_IO00 0x19 /* GPIO_A_0 */
+ MX8MP_IOMUXC_GPIO1_IO01__GPIO1_IO01 0x19 /* GPIO_A_1 */
+ MX8MP_IOMUXC_GPIO1_IO05__GPIO1_IO05 0x19 /* GPIO_A_2 */
+ MX8MP_IOMUXC_GPIO1_IO08__GPIO1_IO08 0x19 /* GPIO_A_5 */
+ >;
+};
+
&pwm1 {
status = "okay";
};
@@ -108,4 +120,11 @@ pinctrl_panel_stby: panelstbygrp {
MX8MP_IOMUXC_SAI3_RXFS__GPIO4_IO28 0x19
>;
};
+
+ pinctrl_touch: touchgrp {
+ fsl,pins = <
+ MX8MP_IOMUXC_GPIO1_IO06__GPIO1_IO06 0x19
+ MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07 0x150
+ >;
+ };
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-kontron-osm-s.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-kontron-osm-s.dtsi
index b97bfeb1c30f..bc1a261bb000 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-kontron-osm-s.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-kontron-osm-s.dtsi
@@ -330,6 +330,12 @@ rv3028: rtc@52 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_rtc>;
interrupts-extended = <&gpio3 24 IRQ_TYPE_LEVEL_LOW>;
+ /*
+ * While specifying the vdd-supply is normally not strictly necessary,
+ * here it also makes sure that the PMIC driver enables the level-
+ * shifter for the RTC before the RTC is probed.
+ */
+ vdd-supply = <®_vdd_3v3>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-kontron-smarc-eval-carrier.dts b/arch/arm64/boot/dts/freescale/imx8mp-kontron-smarc-eval-carrier.dts
index 2173a36ff691..74d620dd06b7 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-kontron-smarc-eval-carrier.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-kontron-smarc-eval-carrier.dts
@@ -249,6 +249,5 @@ &usb3_phy1 {
};
&usdhc2 {
- vmmc-supply = <®_vdd_3v3>;
status = "okay";
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts b/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts
index 4a4f7c1adc23..9dedb9f11145 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts
@@ -356,7 +356,7 @@ MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA 0x400001c3
pinctrl_pmic: pmicgrp {
fsl,pins = <
- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41
+ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0
>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-nitrogen-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-nitrogen-som.dtsi
index f658309612ef..8465b36d440a 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-nitrogen-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-nitrogen-som.dtsi
@@ -296,7 +296,7 @@ MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA 0x400001c3
pinctrl_pmic: pmicirqgrp {
fsl,pins = <
- MX8MP_IOMUXC_NAND_ALE__GPIO3_IO00 0x41
+ MX8MP_IOMUXC_NAND_ALE__GPIO3_IO00 0x1c0
>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi
index 3cdb0bc0ab72..c3f7daa773ea 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi
@@ -174,7 +174,7 @@ pmic: pmic@25 {
pinctrl-0 = <&pmic_pins>;
pinctrl-names = "default";
interrupt-parent = <&gpio1>;
- interrupts = <3 GPIO_ACTIVE_LOW>;
+ interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
nxp,i2c-lt-enable;
regulators {
@@ -417,7 +417,7 @@ MX8MP_IOMUXC_SAI1_RXD1__GPIO4_IO03 0x160
pmic_pins: pinctrl-pmic-grp {
fsl,pins = <
- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41
+ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0
>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts
index b7f69c92b774..1665a5030b99 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts
@@ -848,8 +848,8 @@ pinctrl_tlv320aic3x04: tlv320aic3x04grp {
pinctrl_uart1: uart1grp {
fsl,pins = <MX8MP_IOMUXC_SAI2_RXFS__UART1_DCE_TX 0x14>,
<MX8MP_IOMUXC_SAI2_RXC__UART1_DCE_RX 0x14>,
- <MX8MP_IOMUXC_SAI2_RXD0__UART1_DTE_CTS 0x14>,
- <MX8MP_IOMUXC_SAI2_TXFS__UART1_DTE_RTS 0x14>;
+ <MX8MP_IOMUXC_SAI2_RXD0__UART1_DCE_RTS 0x14>,
+ <MX8MP_IOMUXC_SAI2_TXFS__UART1_DCE_CTS 0x14>;
};
pinctrl_uart1_gpio: uart1gpiogrp {
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts b/arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts
index 9ecec1a41878..3e6f9c88cc20 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts
@@ -275,7 +275,7 @@ pmic@25 {
reg = <0x25>;
pinctrl-0 = <&pinctrl_pmic>;
interrupt-parent = <&gpio1>;
- interrupts = <3 GPIO_ACTIVE_LOW>;
+ interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
/*
* i.MX 8M Plus Data Sheet for Consumer Products
@@ -739,7 +739,7 @@ MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07 0x40 /* NFC_INT */
pinctrl_pmic: pmic-grp {
fsl,pins = <
- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x40 /* #PMIC_INT */
+ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 /* #PMIC_INT */
>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts
index dadc136aec6e..011a89d85961 100644
--- a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts
+++ b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts
@@ -611,9 +611,17 @@ ptn5110: tcpc@51 {
usb_con1: connector {
compatible = "usb-c-connector";
label = "USB-C";
- power-role = "source";
+ power-role = "dual";
data-role = "dual";
+ try-power-role = "sink";
source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+ /*
+ * Set operational current to 0mA as we don't want EN_SNK
+ * enable 12V VBUS switch when it work as a sink.
+ */
+ sink-pdos = <PDO_FIXED(5000, 0, PDO_FIXED_USB_COMM)>;
+ op-sink-microwatt = <0>;
+ self-powered;
ports {
#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts
index 40a0bc9f4e84..623169f7ddb5 100644
--- a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts
+++ b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts
@@ -566,9 +566,17 @@ ptn5110: tcpc@50 {
usb_con1: connector {
compatible = "usb-c-connector";
label = "USB-C";
- power-role = "source";
+ power-role = "dual";
data-role = "dual";
+ try-power-role = "sink";
source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+ /*
+ * Set operational current to 0mA as we don't want EN_SNK
+ * enable 12V VBUS switch when it work as a sink.
+ */
+ sink-pdos = <PDO_FIXED(5000, 0, PDO_FIXED_USB_COMM)>;
+ op-sink-microwatt = <0>;
+ self-powered;
ports {
#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
index 03f460d62f7a..6a066a0d86bc 100644
--- a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
@@ -514,6 +514,7 @@ &usdhc1 {
pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
pinctrl-names = "default", "state_100mhz", "state_200mhz";
+ fsl,tuning-step = <1>;
status = "okay";
};
@@ -528,6 +529,7 @@ &usdhc2 {
pinctrl-3 = <&pinctrl_usdhc2_sleep>, <&pinctrl_usdhc2_gpio_sleep>;
pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
vmmc-supply = <®_usdhc2_vmmc>;
+ fsl,tuning-step = <1>;
status = "okay";
};
diff --git a/arch/arm64/boot/dts/freescale/imx91.dtsi b/arch/arm64/boot/dts/freescale/imx91.dtsi
index f075592bfc01..d63569b39bbc 100644
--- a/arch/arm64/boot/dts/freescale/imx91.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx91.dtsi
@@ -11,7 +11,7 @@ thermal-zones {
cpu-thermal {
polling-delay-passive = <250>;
polling-delay = <2000>;
- thermal-sensors = <&tmu 0>;
+ thermal-sensors = <&tmu>;
trips {
cpu_alert: cpu-alert {
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi
index cd856c0aba71..12deacb741cc 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi
@@ -161,7 +161,7 @@ ð1 {
&usb3 {
status = "okay";
phys = <&usb2_utmi_otg_phy>;
- phy-names = "usb2-utmi-otg-phy";
+ phy-names = "usb2-phy";
};
&uart0 {
diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index 87f9367aec12..cbc411bfa381 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -373,7 +373,7 @@ usb3: usb@58000 {
interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&sb_periph_clk 12>;
phys = <&comphy0 0>, <&usb2_utmi_otg_phy>;
- phy-names = "usb3-phy", "usb2-utmi-otg-phy";
+ phy-names = "usb3-phy", "usb2-phy";
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/mediatek/mt6795.dtsi b/arch/arm64/boot/dts/mediatek/mt6795.dtsi
index ae2aaa51c9ad..134cfa77e3b1 100644
--- a/arch/arm64/boot/dts/mediatek/mt6795.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt6795.dtsi
@@ -371,7 +371,7 @@ pio: pinctrl@10005000 {
<GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>;
- gpio-ranges = <&pio 0 0 196>;
+ gpio-ranges = <&pio 0 0 197>;
interrupt-controller;
#interrupt-cells = <2>;
};
diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi
index 4084f4dfa3e5..1bbe219380f9 100644
--- a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi
@@ -332,7 +332,7 @@ pio: pinctrl@11d00000 {
interrupt-controller;
interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
interrupt-parent = <&gic>;
- gpio-ranges = <&pio 0 0 56>;
+ gpio-ranges = <&pio 0 0 57>;
gpio-controller;
#gpio-cells = <2>;
#interrupt-cells = <2>;
diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
index 9693f62fd013..9ebc196107e5 100644
--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
@@ -187,7 +187,7 @@ pio: pinctrl@1001f000 {
"iocfg_lb", "iocfg_tr", "iocfg_tl", "eint";
gpio-controller;
#gpio-cells = <2>;
- gpio-ranges = <&pio 0 0 100>;
+ gpio-ranges = <&pio 0 0 101>;
interrupt-controller;
interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
interrupt-parent = <&gic>;
diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-4e.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-4e.dts
index c7ea6e88c4f4..621d01e3cd89 100644
--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-4e.dts
+++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-4e.dts
@@ -9,7 +9,7 @@
#include "mt7988a-bananapi-bpi-r4-pro.dtsi"
/ {
- model = "Bananapi BPI-R4";
+ model = "Bananapi BPI-R4 Pro 4E";
compatible = "bananapi,bpi-r4-pro-4e",
"bananapi,bpi-r4-pro",
"mediatek,mt7988a";
diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-8x.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-8x.dts
index c9a0e69e9dd5..bb15bfa5e6ae 100644
--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-8x.dts
+++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-8x.dts
@@ -9,7 +9,7 @@
#include "mt7988a-bananapi-bpi-r4-pro.dtsi"
/ {
- model = "Bananapi BPI-R4";
+ model = "Bananapi BPI-R4 Pro 8X";
compatible = "bananapi,bpi-r4-pro-8x",
"bananapi,bpi-r4-pro",
"mediatek,mt7988a";
diff --git a/arch/arm64/boot/dts/mediatek/mt8365.dtsi b/arch/arm64/boot/dts/mediatek/mt8365.dtsi
index a5ca3cda6ef3..2e782558fb77 100644
--- a/arch/arm64/boot/dts/mediatek/mt8365.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8365.dtsi
@@ -536,10 +536,9 @@ iommu: iommu@10205000 {
#iommu-cells = <1>;
};
- infracfg_nao: infracfg@1020e000 {
- compatible = "mediatek,mt8365-infracfg", "syscon";
+ infracfg_nao: syscon@1020e000 {
+ compatible = "mediatek,mt8365-infracfg-nao", "syscon";
reg = <0 0x1020e000 0 0x1000>;
- #clock-cells = <1>;
};
rng: rng@1020f000 {
diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3701.dtsi b/arch/arm64/boot/dts/nvidia/tegra234-p3701.dtsi
index 58bf55c0e414..c10d041c183b 100644
--- a/arch/arm64/boot/dts/nvidia/tegra234-p3701.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra234-p3701.dtsi
@@ -9,6 +9,7 @@ aliases {
mmc0 = "/bus@0/mmc@3460000";
mmc1 = "/bus@0/mmc@3400000";
rtc0 = "/bpmp/i2c/pmic@3c";
+ rtc1 = "/bus@0/rtc@c2a0000";
};
bus@0 {
diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi b/arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi
index ab391a71c3d3..9e9e80d57623 100644
--- a/arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi
@@ -8,6 +8,7 @@ / {
aliases {
mmc0 = "/bus@0/mmc@3400000";
rtc0 = "/bpmp/i2c/pmic@3c";
+ rtc1 = "/bus@0/rtc@c2a0000";
};
bus@0 {
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index f80b5d9cf1e8..b05e8adc02f6 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -374,6 +374,8 @@ x1e80100-lenovo-yoga-slim7x-el2-dtbs := x1e80100-lenovo-yoga-slim7x.dtb x1-el2.d
dtb-$(CONFIG_ARCH_QCOM) += x1e80100-lenovo-yoga-slim7x.dtb x1e80100-lenovo-yoga-slim7x-el2.dtb
x1e80100-medion-sprchrgd-14-s1-el2-dtbs := x1e80100-medion-sprchrgd-14-s1.dtb x1-el2.dtbo
dtb-$(CONFIG_ARCH_QCOM) += x1e80100-medion-sprchrgd-14-s1.dtb x1e80100-medion-sprchrgd-14-s1-el2.dtb
+x1e80100-microsoft-denali-oled-el2-dtbs := x1e80100-microsoft-denali-oled.dtb x1-el2.dtbo
+dtb-$(CONFIG_ARCH_QCOM) += x1e80100-microsoft-denali-oled.dtb x1e80100-microsoft-denali-oled-el2.dtb
x1e80100-microsoft-romulus13-el2-dtbs := x1e80100-microsoft-romulus13.dtb x1-el2.dtbo
dtb-$(CONFIG_ARCH_QCOM) += x1e80100-microsoft-romulus13.dtb x1e80100-microsoft-romulus13-el2.dtb
x1e80100-microsoft-romulus15-el2-dtbs := x1e80100-microsoft-romulus15.dtb x1-el2.dtbo
diff --git a/arch/arm64/boot/dts/qcom/hamoa.dtsi b/arch/arm64/boot/dts/qcom/hamoa.dtsi
index 4b0784af4bd3..cb95549275ca 100644
--- a/arch/arm64/boot/dts/qcom/hamoa.dtsi
+++ b/arch/arm64/boot/dts/qcom/hamoa.dtsi
@@ -4714,7 +4714,7 @@ sdhc_2: mmc@8804000 {
clocks = <&gcc GCC_SDCC2_AHB_CLK>,
<&gcc GCC_SDCC2_APPS_CLK>,
- <&rpmhcc RPMH_CXO_CLK>;
+ <&bi_tcxo_div2>;
clock-names = "iface", "core", "xo";
iommus = <&apps_smmu 0x520 0>;
qcom,dll-config = <0x0007642c>;
@@ -4767,7 +4767,7 @@ sdhc_4: mmc@8844000 {
clocks = <&gcc GCC_SDCC4_AHB_CLK>,
<&gcc GCC_SDCC4_APPS_CLK>,
- <&rpmhcc RPMH_CXO_CLK>;
+ <&bi_tcxo_div2>;
clock-names = "iface", "core", "xo";
iommus = <&apps_smmu 0x160 0>;
qcom,dll-config = <0x0007642c>;
@@ -5432,19 +5432,19 @@ opp-338000000 {
opp-366000000 {
opp-hz = /bits/ 64 <366000000>;
- required-opps = <&rpmhpd_opp_svs_l1>,
+ required-opps = <&rpmhpd_opp_svs>,
<&rpmhpd_opp_svs_l1>;
};
opp-444000000 {
opp-hz = /bits/ 64 <444000000>;
- required-opps = <&rpmhpd_opp_nom>,
+ required-opps = <&rpmhpd_opp_svs_l1>,
<&rpmhpd_opp_nom>;
};
opp-481000000 {
opp-hz = /bits/ 64 <481000000>;
- required-opps = <&rpmhpd_opp_turbo>,
+ required-opps = <&rpmhpd_opp_svs_l1>,
<&rpmhpd_opp_turbo>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/kaanapali.dtsi b/arch/arm64/boot/dts/qcom/kaanapali.dtsi
index 9ef57ad0ca71..9be86479ceef 100644
--- a/arch/arm64/boot/dts/qcom/kaanapali.dtsi
+++ b/arch/arm64/boot/dts/qcom/kaanapali.dtsi
@@ -1239,7 +1239,7 @@ intc: interrupt-controller@17000000 {
gic_its: msi-controller@17040000 {
compatible = "arm,gic-v3-its";
- reg = <0x0 0x17040000 0x0 0x20000>;
+ reg = <0x0 0x17040000 0x0 0x40000>;
msi-controller;
#msi-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi
index 2db2ab9cb2e0..be8c8c59ef5a 100644
--- a/arch/arm64/boot/dts/qcom/lemans.dtsi
+++ b/arch/arm64/boot/dts/qcom/lemans.dtsi
@@ -4625,19 +4625,19 @@ opp-366000000 {
opp-444000000 {
opp-hz = /bits/ 64 <444000000>;
- required-opps = <&rpmhpd_opp_nom>,
+ required-opps = <&rpmhpd_opp_svs_l1>,
<&rpmhpd_opp_nom>;
};
opp-533000000 {
opp-hz = /bits/ 64 <533000000>;
- required-opps = <&rpmhpd_opp_turbo>,
+ required-opps = <&rpmhpd_opp_nom>,
<&rpmhpd_opp_turbo>;
};
opp-560000000 {
opp-hz = /bits/ 64 <560000000>;
- required-opps = <&rpmhpd_opp_turbo_l1>,
+ required-opps = <&rpmhpd_opp_nom>,
<&rpmhpd_opp_turbo_l1>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/milos.dtsi b/arch/arm64/boot/dts/qcom/milos.dtsi
index e1a51d43943f..098f9ceaa4f3 100644
--- a/arch/arm64/boot/dts/qcom/milos.dtsi
+++ b/arch/arm64/boot/dts/qcom/milos.dtsi
@@ -802,6 +802,8 @@ gcc: clock-controller@100000 {
<0>, /* ufs_phy_tx_symbol_0_clk */
<0>; /* usb3_phy_wrapper_gcc_usb30_pipe_clk */
+ power-domains = <&rpmhpd RPMHPD_CX>;
+
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
@@ -1911,7 +1913,7 @@ ppi_cluster1: interrupt-partition-1 {
gic_its: msi-controller@17140000 {
compatible = "arm,gic-v3-its";
- reg = <0x0 0x17140000 0x0 0x20000>;
+ reg = <0x0 0x17140000 0x0 0x40000>;
msi-controller;
#msi-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
index 0cb9fd154b68..37d0515e8893 100644
--- a/arch/arm64/boot/dts/qcom/monaco.dtsi
+++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
@@ -5293,19 +5293,19 @@ opp-366000000 {
opp-444000000 {
opp-hz = /bits/ 64 <444000000>;
- required-opps = <&rpmhpd_opp_nom>,
+ required-opps = <&rpmhpd_opp_svs_l1>,
<&rpmhpd_opp_nom>;
};
opp-533000000 {
opp-hz = /bits/ 64 <533000000>;
- required-opps = <&rpmhpd_opp_turbo>,
+ required-opps = <&rpmhpd_opp_nom>,
<&rpmhpd_opp_turbo>;
};
opp-560000000 {
opp-hz = /bits/ 64 <560000000>;
- required-opps = <&rpmhpd_opp_turbo_l1>,
+ required-opps = <&rpmhpd_opp_nom>,
<&rpmhpd_opp_turbo_l1>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-xiaomi-riva.dts b/arch/arm64/boot/dts/qcom/msm8917-xiaomi-riva.dts
index 9db503e21888..1bfb16f90ddd 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-xiaomi-riva.dts
+++ b/arch/arm64/boot/dts/qcom/msm8917-xiaomi-riva.dts
@@ -18,7 +18,7 @@ / {
chassis-type = "handset";
qcom,msm-id = <QCOM_ID_MSM8917 0>;
- qcom,board-id = <0x1000b 2>, <0x2000b 2>;
+ qcom,board-id = <0x1000b 1>, <0x1000b 2>;
pwm_backlight: backlight {
compatible = "pwm-backlight";
diff --git a/arch/arm64/boot/dts/qcom/msm8937-xiaomi-land.dts b/arch/arm64/boot/dts/qcom/msm8937-xiaomi-land.dts
index 91837ff940f1..4f301e7c6517 100644
--- a/arch/arm64/boot/dts/qcom/msm8937-xiaomi-land.dts
+++ b/arch/arm64/boot/dts/qcom/msm8937-xiaomi-land.dts
@@ -178,7 +178,7 @@ &pmi8950_wled {
qcom,num-strings = <2>;
qcom,external-pfet;
qcom,current-limit-microamp = <20000>;
- qcom,ovp-millivolt = <29600>;
+ qcom,ovp-millivolt = <29500>;
status = "okay";
};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts
index ddd7af616794..59f873a06e4d 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts
@@ -157,7 +157,7 @@ &pm8953_resin {
&pmi8950_wled {
qcom,current-limit-microamp = <20000>;
- qcom,num-strings = <2>;
+ qcom,num-strings = <3>;
status = "okay";
};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts
index d46325e79917..c2a290bf493c 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts
@@ -169,7 +169,7 @@ &pm8953_resin {
&pmi8950_wled {
qcom,current-limit-microamp = <20000>;
- qcom,ovp-millivolt = <29600>;
+ qcom,ovp-millivolt = <29500>;
qcom,num-strings = <2>;
qcom,external-pfet;
qcom,cabc;
diff --git a/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts b/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts
index 0b64a0b91202..f47efca42d48 100644
--- a/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts
+++ b/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts
@@ -755,10 +755,10 @@ ports {
#address-cells = <1>;
#size-cells = <0>;
- port@0 {
- reg = <0>;
+ port@1 {
+ reg = <1>;
- lt9611_a: endpoint {
+ lt9611_b: endpoint {
remote-endpoint = <&mdss_dsi0_out>;
};
};
@@ -801,7 +801,7 @@ &mdss_dsi {
};
&mdss_dsi0_out {
- remote-endpoint = <<9611_a>;
+ remote-endpoint = <<9611_b>;
data-lanes = <0 1 2 3>;
};
diff --git a/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts b/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts
index 197ab6eb1666..5ab605cc56c8 100644
--- a/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts
+++ b/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts
@@ -325,21 +325,13 @@ &sdhc_1 {
&spi5 {
status = "okay";
- spidev@0 {
- reg = <0>;
+ mcu@0 {
compatible = "arduino,unoq-mcu";
- pinctrl-0 = <&spidev_cs>;
- pinctrl-names = "default";
+ reg = <0>;
};
};
&tlmm {
- spidev_cs: spidev-cs-state {
- pins = "gpio17";
- function = "gpio";
- drive-strength = <16>;
- };
-
jmisc_gpio18: jmisc-gpio18-state {
pins = "gpio18";
function = "gpio";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi
index 01b570d0880d..1298485c4214 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi
@@ -148,6 +148,7 @@ vreg_l1a_0p875: ldo1 {
regulator-min-microvolt = <880000>;
regulator-max-microvolt = <880000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-boot-on;
};
vreg_l5a_0p8: ldo5 {
diff --git a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts
index 6b68e391cf3e..c3edeee3af3e 100644
--- a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts
+++ b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts
@@ -13,14 +13,18 @@
#include "sm6125.dtsi"
#include "pm6125.dtsi"
+/delete-node/ &adsp_pil_mem;
+/delete-node/ &cont_splash_mem;
+/delete-node/ &gpu_mem;
+/delete-node/ &ipa_fw_mem;
+/delete-node/ &ipa_gsi_mem;
+
/ {
model = "Xiaomi Redmi Note 8";
compatible = "xiaomi,ginkgo", "qcom,sm6125";
chassis-type = "handset";
- /* required for bootloader to select correct board */
qcom,msm-id = <QCOM_ID_SM6125 0x10000>;
- qcom,board-id = <22 0>;
chosen {
#address-cells = <2>;
@@ -38,33 +42,39 @@ framebuffer0: framebuffer@5c000000 {
};
reserved-memory {
- debug_mem: debug@ffb00000 {
- reg = <0x0 0xffb00000 0x0 0xc0000>;
+ adsp_pil_mem: adsp_pil_mem@55300000 {
+ reg = <0x0 0x55300000 0x0 0x2200000>;
no-map;
};
- last_log_mem: lastlog@ffbc0000 {
- reg = <0x0 0xffbc0000 0x0 0x80000>;
+ ipa_fw_mem: ipa_fw_mem@57500000 {
+ reg = <0x0 0x57500000 0x0 0x10000>;
no-map;
};
- pstore_mem: ramoops@ffc00000 {
- compatible = "ramoops";
- reg = <0x0 0xffc40000 0x0 0xc0000>;
- record-size = <0x1000>;
- console-size = <0x40000>;
- pmsg-size = <0x20000>;
+ ipa_gsi_mem: ipa_gsi_mem@57510000 {
+ reg = <0x0 0x57510000 0x0 0x5000>;
+ no-map;
};
- cmdline_mem: memory@ffd00000 {
- reg = <0x0 0xffd40000 0x0 0x1000>;
+ gpu_mem: gpu_mem@57515000 {
+ reg = <0x0 0x57515000 0x0 0x2000>;
no-map;
};
- };
- extcon_usb: extcon-usb {
- compatible = "linux,extcon-usb-gpio";
- id-gpios = <&tlmm 102 GPIO_ACTIVE_HIGH>;
+ framebuffer@5c000000 {
+ reg = <0x0 0x5c000000 0x0 (2340 * 1080 * 4)>;
+ no-map;
+ };
+
+ /* Matching with recovery values to be able to get the results. */
+ ramoops@61600000 {
+ compatible = "ramoops";
+ reg = <0x0 0x61600000 0x0 0x400000>;
+ record-size = <0x80000>;
+ pmsg-size = <0x200000>;
+ console-size = <0x100000>;
+ };
};
gpio-keys {
@@ -283,13 +293,9 @@ &sdhc_2 {
};
&tlmm {
- gpio-reserved-ranges = <22 2>, <28 6>;
+ gpio-reserved-ranges = <0 4>, <30 4>;
};
&usb3 {
status = "okay";
};
-
-&usb3_dwc3 {
- extcon = <&extcon_usb>;
-};
diff --git a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts
index a3c2b26736f4..3964aae47fd4 100644
--- a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts
+++ b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts
@@ -1019,12 +1019,14 @@ &qup_uart1_cts {
* the Bluetooth module drives the pin in either
* direction or leaves the pin fully unpowered.
*/
+ /delete-property/ bias-disable;
bias-bus-hold;
};
&qup_uart1_rts {
/* We'll drive RTS, so no pull */
drive-strength = <2>;
+ /delete-property/ bias-pull-down;
bias-disable;
};
@@ -1035,12 +1037,14 @@ &qup_uart1_rx {
* in tri-state (module powered off or not driving the
* signal yet).
*/
+ /delete-property/ bias-disable;
bias-pull-up;
};
&qup_uart1_tx {
/* We'll drive TX, so no pull */
drive-strength = <2>;
+ /delete-property/ bias-pull-up;
bias-disable;
};
diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi
index c7dffa440074..37c41cc1abdd 100644
--- a/arch/arm64/boot/dts/qcom/sm8250.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi
@@ -665,6 +665,11 @@ cpu7_opp20: opp-2841600000 {
opp-hz = /bits/ 64 <2841600000>;
opp-peak-kBps = <8368000 51609600>;
};
+
+ cpu7_opp21: opp-3091200000 {
+ opp-hz = /bits/ 64 <3091200000>;
+ opp-peak-kBps = <8368000 51609600>;
+ };
};
firmware {
diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi
index 920a2d1c04d0..dd60843e022e 100644
--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi
@@ -5104,7 +5104,7 @@ intc: interrupt-controller@17100000 {
gic_its: msi-controller@17140000 {
compatible = "arm,gic-v3-its";
- reg = <0x0 0x17140000 0x0 0x20000>;
+ reg = <0x0 0x17140000 0x0 0x40000>;
msi-controller;
#msi-cells = <1>;
};
@@ -5429,9 +5429,6 @@ sdhc_2: mmc@8804000 {
bus-width = <4>;
dma-coherent;
- /* Forbid SDR104/SDR50 - broken hw! */
- sdhci-caps-mask = <0x3 0x0>;
-
status = "disabled";
sdhc2_opp_table: opp-table {
diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi
index e3f93f4f412d..42f9deaadd86 100644
--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi
@@ -3210,7 +3210,7 @@ sdhc_2: mmc@8804000 {
clocks = <&gcc GCC_SDCC2_AHB_CLK>,
<&gcc GCC_SDCC2_APPS_CLK>,
- <&rpmhcc RPMH_CXO_CLK>;
+ <&bi_tcxo_div2>;
clock-names = "iface", "core", "xo";
iommus = <&apps_smmu 0x540 0>;
qcom,dll-config = <0x0007642c>;
@@ -3227,9 +3227,6 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
max-sd-hs-hz = <37500000>;
dma-coherent;
- /* Forbid SDR104/SDR50 - broken hw! */
- sdhci-caps-mask = <0x3 0>;
-
status = "disabled";
sdhc2_opp_table: opp-table {
@@ -3320,19 +3317,19 @@ opp-338000000 {
opp-366000000 {
opp-hz = /bits/ 64 <366000000>;
- required-opps = <&rpmhpd_opp_svs_l1>,
+ required-opps = <&rpmhpd_opp_svs>,
<&rpmhpd_opp_svs_l1>;
};
opp-444000000 {
opp-hz = /bits/ 64 <444000000>;
- required-opps = <&rpmhpd_opp_nom>,
+ required-opps = <&rpmhpd_opp_svs_l1>,
<&rpmhpd_opp_nom>;
};
opp-533333334 {
opp-hz = /bits/ 64 <533333334>;
- required-opps = <&rpmhpd_opp_turbo>,
+ required-opps = <&rpmhpd_opp_nom>,
<&rpmhpd_opp_turbo>;
};
};
@@ -5274,7 +5271,7 @@ ppi_cluster3: interrupt-partition-3 {
gic_its: msi-controller@17140000 {
compatible = "arm,gic-v3-its";
- reg = <0 0x17140000 0 0x20000>;
+ reg = <0 0x17140000 0 0x40000>;
msi-controller;
#msi-cells = <1>;
};
diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi
index 357e43b90740..64a7480291d8 100644
--- a/arch/arm64/boot/dts/qcom/sm8650.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi
@@ -4957,7 +4957,7 @@ sdhc_2: mmc@8804000 {
clocks = <&gcc GCC_SDCC2_AHB_CLK>,
<&gcc GCC_SDCC2_APPS_CLK>,
- <&rpmhcc RPMH_CXO_CLK>;
+ <&bi_tcxo_div2>;
clock-names = "iface",
"core",
"xo";
@@ -4976,9 +4976,6 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
bus-width = <4>;
- /* Forbid SDR104/SDR50 - broken hw! */
- sdhci-caps-mask = <0x3 0>;
-
qcom,dll-config = <0x0007642c>;
qcom,ddr-config = <0x80040868>;
@@ -5236,13 +5233,13 @@ opp-196000000 {
opp-300000000 {
opp-hz = /bits/ 64 <300000000>;
- required-opps = <&rpmhpd_opp_low_svs>,
+ required-opps = <&rpmhpd_opp_svs>,
<&rpmhpd_opp_low_svs>;
};
opp-380000000 {
opp-hz = /bits/ 64 <380000000>;
- required-opps = <&rpmhpd_opp_svs>,
+ required-opps = <&rpmhpd_opp_svs_l1>,
<&rpmhpd_opp_svs>;
};
@@ -5254,13 +5251,13 @@ opp-435000000 {
opp-480000000 {
opp-hz = /bits/ 64 <480000000>;
- required-opps = <&rpmhpd_opp_nom>,
+ required-opps = <&rpmhpd_opp_svs_l1>,
<&rpmhpd_opp_nom>;
};
opp-533333334 {
opp-hz = /bits/ 64 <533333334>;
- required-opps = <&rpmhpd_opp_turbo>,
+ required-opps = <&rpmhpd_opp_svs_l1>,
<&rpmhpd_opp_turbo>;
};
};
@@ -7219,7 +7216,7 @@ ppi_cluster2: interrupt-partition-2 {
gic_its: msi-controller@17140000 {
compatible = "arm,gic-v3-its";
- reg = <0 0x17140000 0 0x20000>;
+ reg = <0 0x17140000 0 0x40000>;
msi-controller;
#msi-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/sm8750.dtsi b/arch/arm64/boot/dts/qcom/sm8750.dtsi
index f56b1f889b85..4efdead3583f 100644
--- a/arch/arm64/boot/dts/qcom/sm8750.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8750.dtsi
@@ -2945,19 +2945,19 @@ iris_opp_table: opp-table {
opp-240000000 {
opp-hz = /bits/ 64 <240000000>;
- required-opps = <&rpmhpd_opp_low_svs_d1>,
+ required-opps = <&rpmhpd_opp_svs>,
<&rpmhpd_opp_low_svs_d1>;
};
opp-338000000 {
opp-hz = /bits/ 64 <338000000>;
- required-opps = <&rpmhpd_opp_low_svs>,
+ required-opps = <&rpmhpd_opp_svs>,
<&rpmhpd_opp_low_svs>;
};
opp-420000000 {
opp-hz = /bits/ 64 <420000000>;
- required-opps = <&rpmhpd_opp_svs>,
+ required-opps = <&rpmhpd_opp_svs_l1>,
<&rpmhpd_opp_svs>;
};
@@ -2969,19 +2969,19 @@ opp-444000000 {
opp-533333334 {
opp-hz = /bits/ 64 <533333334>;
- required-opps = <&rpmhpd_opp_nom>,
+ required-opps = <&rpmhpd_opp_svs_l1>,
<&rpmhpd_opp_nom>;
};
opp-570000000 {
opp-hz = /bits/ 64 <570000000>;
- required-opps = <&rpmhpd_opp_nom_l1>,
+ required-opps = <&rpmhpd_opp_nom>,
<&rpmhpd_opp_nom_l1>;
};
opp-630000000 {
opp-hz = /bits/ 64 <630000000>;
- required-opps = <&rpmhpd_opp_turbo>,
+ required-opps = <&rpmhpd_opp_nom>,
<&rpmhpd_opp_turbo>;
};
};
@@ -4658,7 +4658,7 @@ intc: interrupt-controller@16000000 {
gic_its: msi-controller@16040000 {
compatible = "arm,gic-v3-its";
- reg = <0x0 0x16040000 0x0 0x20000>;
+ reg = <0x0 0x16040000 0x0 0x40000>;
msi-controller;
#msi-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi
index 75716b4a58d6..6dab0d5dcbb8 100644
--- a/arch/arm64/boot/dts/qcom/talos.dtsi
+++ b/arch/arm64/boot/dts/qcom/talos.dtsi
@@ -666,6 +666,9 @@ gcc: clock-controller@100000 {
clocks = <&rpmhcc RPMH_CXO_CLK>,
<&rpmhcc RPMH_CXO_CLK_A>,
<&sleep_clk>;
+ clock-names = "bi_tcxo",
+ "bi_tcxo_ao",
+ "sleep_clk";
#clock-cells = <1>;
#reset-cells = <1>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts
index 30bdb38f0727..e810ed146451 100644
--- a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts
@@ -58,24 +58,6 @@ ir-receiver {
gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_LOW>;
linux,rc-map-name = "rc-beelink-gs1";
};
-
- spdif_dit: spdif-dit {
- compatible = "linux,spdif-dit";
- #sound-dai-cells = <0>;
- };
-
- spdif_sound: spdif-sound {
- compatible = "simple-audio-card";
- simple-audio-card,name = "SPDIF";
-
- simple-audio-card,cpu {
- sound-dai = <&spdif>;
- };
-
- simple-audio-card,codec {
- sound-dai = <&spdif_dit>;
- };
- };
};
&analog_sound {
@@ -343,11 +325,6 @@ &sdmmc {
status = "okay";
};
-&spdif {
- pinctrl-0 = <&spdifm0_tx>;
- status = "okay";
-};
-
&tsadc {
rockchip,hw-tshut-mode = <0>;
rockchip,hw-tshut-polarity = <0>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3562-evb2-v10.dts b/arch/arm64/boot/dts/rockchip/rk3562-evb2-v10.dts
index 6a84db154a7d..387062eea520 100644
--- a/arch/arm64/boot/dts/rockchip/rk3562-evb2-v10.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3562-evb2-v10.dts
@@ -13,7 +13,7 @@
#include "rk3562.dtsi"
/ {
- model = "Rockchip RK3562 EVB V20 Board";
+ model = "Rockchip RK3562 EVB2 V10 Board";
compatible = "rockchip,rk3562-evb2-v10", "rockchip,rk3562";
chosen: chosen {
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts b/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts
index ed65d3120444..18a560a6e2a4 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts
@@ -635,10 +635,10 @@ &uart1 {
status = "okay";
bluetooth: bluetooth {
- compatible = "brcm,bcm43438-bt";
+ compatible = "brcm,bcm43430a1-bt";
clocks = <&rk809 1>;
clock-names = "lpo";
- max-speed = <3000000>;
+ max-speed = <1500000>;
pinctrl-names = "default";
pinctrl-0 = <&bt_host_wake_l &bt_wake_l &bt_enable_h>;
shutdown-gpios = <&gpio2 RK_PB7 GPIO_ACTIVE_HIGH>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi
index 49ccdf12ef7e..8149e2bbde79 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi
@@ -1868,8 +1868,9 @@ ufshc: ufshc@2a2d0000 {
pinctrl-0 = <&ufs_refclk &ufs_rstgpio>;
pinctrl-names = "default";
resets = <&cru SRST_A_UFS_BIU>, <&cru SRST_A_UFS_SYS>,
- <&cru SRST_A_UFS>, <&cru SRST_P_UFS_GRF>;
- reset-names = "biu", "sys", "ufs", "grf";
+ <&cru SRST_A_UFS>, <&cru SRST_P_UFS_GRF>,
+ <&cru SRST_MPHY_INIT>;
+ reset-names = "biu", "sys", "ufs", "grf", "mphy";
reset-gpios = <&gpio4 RK_PD0 GPIO_ACTIVE_LOW>;
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts b/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts
index 952affaf455c..500a0bad1ea3 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts
@@ -588,7 +588,7 @@ led1_pin: led1-pin {
pcie30x4 {
pcie30x4_clkreqn_m0: pcie30x4-clkreqn-m0 {
- rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+ rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>;
};
pcie30x4_perstn_m0: pcie30x4-perstn-m0 {
diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts b/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts
index e8ad525ba3f9..89618394c0bf 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts
@@ -60,8 +60,8 @@ axis@0 {
reg = <0>;
abs-flat = <40>;
abs-fuzz = <30>;
- abs-range = <0 4095>;
- linux,code = <ABS_RX>;
+ abs-range = <4095 0>;
+ linux,code = <ABS_RY>;
};
axis@1 {
@@ -69,7 +69,7 @@ axis@1 {
abs-flat = <40>;
abs-fuzz = <30>;
abs-range = <0 4095>;
- linux,code = <ABS_RY>;
+ linux,code = <ABS_RX>;
};
axis@2 {
@@ -77,7 +77,7 @@ axis@2 {
abs-flat = <40>;
abs-fuzz = <30>;
abs-range = <0 4095>;
- linux,code = <ABS_Y>;
+ linux,code = <ABS_X>;
};
axis@3 {
@@ -85,7 +85,7 @@ axis@3 {
abs-flat = <40>;
abs-fuzz = <30>;
abs-range = <0 4095>;
- linux,code = <ABS_X>;
+ linux,code = <ABS_Y>;
};
};
@@ -318,7 +318,7 @@ pwm_fan: pwm-fan {
compatible = "pwm-fan";
#cooling-cells = <2>;
cooling-levels = <0 120 150 180 210 240 255>;
- fan-supply = <&vcc5v0_sys>;
+ fan-supply = <&vcc5v0_spk>;
interrupt-parent = <&gpio4>;
interrupts = <RK_PB2 IRQ_TYPE_EDGE_RISING>;
pulses-per-revolution = <4>;
diff --git a/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts b/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts
index 3e2d8f669535..8a556fbbe08b 100644
--- a/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts
+++ b/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts
@@ -88,13 +88,13 @@ main_mmc0_pins_default: main-mmc0-default-pins {
AM62X_IOPAD(0x220, PIN_INPUT, 0) /* (V3) MMC0_CMD */
AM62X_IOPAD(0x218, PIN_INPUT, 0) /* (Y1) MMC0_CLK */
AM62X_IOPAD(0x214, PIN_INPUT, 0) /* (V2) MMC0_DAT0 */
- AM62X_IOPAD(0x210, PIN_INPUT, 0) /* (V1) MMC0_DAT1 */
- AM62X_IOPAD(0x20c, PIN_INPUT, 0) /* (W2) MMC0_DAT2 */
- AM62X_IOPAD(0x208, PIN_INPUT, 0) /* (W1) MMC0_DAT3 */
- AM62X_IOPAD(0x204, PIN_INPUT, 0) /* (Y2) MMC0_DAT4 */
- AM62X_IOPAD(0x200, PIN_INPUT, 0) /* (W3) MMC0_DAT5 */
- AM62X_IOPAD(0x1fc, PIN_INPUT, 0) /* (W4) MMC0_DAT6 */
- AM62X_IOPAD(0x1f8, PIN_INPUT, 0) /* (V4) MMC0_DAT7 */
+ AM62X_IOPAD(0x210, PIN_INPUT_PULLUP, 0) /* (V1) MMC0_DAT1 */
+ AM62X_IOPAD(0x20c, PIN_INPUT_PULLUP, 0) /* (W2) MMC0_DAT2 */
+ AM62X_IOPAD(0x208, PIN_INPUT_PULLUP, 0) /* (W1) MMC0_DAT3 */
+ AM62X_IOPAD(0x204, PIN_INPUT_PULLUP, 0) /* (Y2) MMC0_DAT4 */
+ AM62X_IOPAD(0x200, PIN_INPUT_PULLUP, 0) /* (W3) MMC0_DAT5 */
+ AM62X_IOPAD(0x1fc, PIN_INPUT_PULLUP, 0) /* (W4) MMC0_DAT6 */
+ AM62X_IOPAD(0x1f8, PIN_INPUT_PULLUP, 0) /* (V4) MMC0_DAT7 */
>;
};
diff --git a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi
index 09840a3b9fe7..20dbfa3001ea 100644
--- a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi
@@ -278,7 +278,7 @@ AM62X_IOPAD(0x0018, PIN_INPUT, 7) /* (F24) OSPI0_D3.GPIO0_6 */ /* SODIMM 62 */
};
/* Verdin SPI_1 CS as GPIO */
- pinctrl_qspi1_io4_gpio: main-gpio0-7-default-pins {
+ pinctrl_spi1_cs_gpio: main-gpio0-7-default-pins {
pinctrl-single,pins = <
AM62X_IOPAD(0x001c, PIN_INPUT, 7) /* (J23) OSPI0_D4.GPIO0_7 */ /* SODIMM 202 */
>;
diff --git a/arch/arm64/boot/dts/ti/k3-am62l.dtsi b/arch/arm64/boot/dts/ti/k3-am62l.dtsi
index 23acdbb301fe..e01e342c26da 100644
--- a/arch/arm64/boot/dts/ti/k3-am62l.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62l.dtsi
@@ -92,7 +92,7 @@ cbass_main: bus@f0000 {
<0x00 0x00b00000 0x00 0x00b00000 0x00 0x00001400>, /* VTM */
<0x00 0x04080000 0x00 0x04080000 0x00 0x00008000>, /* PDCFG */
<0x00 0x04201000 0x00 0x04201000 0x00 0x00000100>, /* GPIO */
- <0x00 0x2b100000 0x00 0x2b100000 0x00 0x00100100>, /* Wakeup Peripheral Window */
+ <0x00 0x2b100000 0x00 0x2b100000 0x00 0x00200200>, /* Wakeup Peripheral Window */
<0x00 0x40800000 0x00 0x40800000 0x00 0x00014000>, /* DMA */
<0x00 0x43000000 0x00 0x43000000 0x00 0x00080000>; /* CTRL MMRs */
#address-cells = <2>;
@@ -104,7 +104,7 @@ cbass_wakeup: bus@a80000 {
<0x00 0x00b00000 0x00 0x00b00000 0x00 0x00001400>, /* VTM */
<0x00 0x04080000 0x00 0x04080000 0x00 0x00008000>, /* PDCFG */
<0x00 0x04201000 0x00 0x04201000 0x00 0x00000100>, /* GPIO */
- <0x00 0x2b100000 0x00 0x2b100000 0x00 0x00100100>, /* Wakeup Peripheral Window */
+ <0x00 0x2b100000 0x00 0x2b100000 0x00 0x00200200>, /* Wakeup Peripheral Window */
<0x00 0x40800000 0x00 0x40800000 0x00 0x00014000>, /* DMA */
<0x00 0x43000000 0x00 0x43000000 0x00 0x00080000>; /* CTRL MMRs */
#address-cells = <2>;
diff --git a/arch/arm64/boot/dts/ti/k3-am62l3-evm.dts b/arch/arm64/boot/dts/ti/k3-am62l3-evm.dts
index cae04cce3373..bd876c68aa34 100644
--- a/arch/arm64/boot/dts/ti/k3-am62l3-evm.dts
+++ b/arch/arm64/boot/dts/ti/k3-am62l3-evm.dts
@@ -272,9 +272,9 @@ mmc1_pins_default: mmc1-default-pins {
AM62LX_IOPAD(0x0230, PIN_INPUT, 0) /* (Y3) MMC1_CMD */
AM62LX_IOPAD(0x0228, PIN_OUTPUT, 0) /* (Y2) MMC1_CLK */
AM62LX_IOPAD(0x0224, PIN_INPUT, 0) /* (AA1) MMC1_DAT0 */
- AM62LX_IOPAD(0x0220, PIN_INPUT_PULLUP, 0) /* (Y4) MMC1_DAT1 */
- AM62LX_IOPAD(0x021c, PIN_INPUT_PULLUP, 0) /* (AA2) MMC1_DAT2 */
- AM62LX_IOPAD(0x0218, PIN_INPUT_PULLUP, 0) /* (AB2) MMC1_DAT3 */
+ AM62LX_IOPAD(0x0220, PIN_INPUT, 0) /* (Y4) MMC1_DAT1 */
+ AM62LX_IOPAD(0x021c, PIN_INPUT, 0) /* (AA2) MMC1_DAT2 */
+ AM62LX_IOPAD(0x0218, PIN_INPUT, 0) /* (AB2) MMC1_DAT3 */
AM62LX_IOPAD(0x0234, PIN_INPUT, 0) /* (B6) MMC1_SDCD */
>;
bootph-all;
diff --git a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts
index 4f7f6f95b02e..35baa777b912 100644
--- a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts
+++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts
@@ -271,9 +271,9 @@ main_mmc1_pins_default: main-mmc1-default-pins {
AM62PX_IOPAD(0x023c, PIN_INPUT, 0) /* (H20) MMC1_CMD */
AM62PX_IOPAD(0x0234, PIN_OUTPUT, 0) /* (J24) MMC1_CLK */
AM62PX_IOPAD(0x0230, PIN_INPUT, 0) /* (H21) MMC1_DAT0 */
- AM62PX_IOPAD(0x022c, PIN_INPUT_PULLUP, 0) /* (H23) MMC1_DAT1 */
- AM62PX_IOPAD(0x0228, PIN_INPUT_PULLUP, 0) /* (H22) MMC1_DAT2 */
- AM62PX_IOPAD(0x0224, PIN_INPUT_PULLUP, 0) /* (H25) MMC1_DAT3 */
+ AM62PX_IOPAD(0x022c, PIN_INPUT, 0) /* (H23) MMC1_DAT1 */
+ AM62PX_IOPAD(0x0228, PIN_INPUT, 0) /* (H22) MMC1_DAT2 */
+ AM62PX_IOPAD(0x0224, PIN_INPUT, 0) /* (H25) MMC1_DAT3 */
AM62PX_IOPAD(0x0240, PIN_INPUT, 0) /* (D23) MMC1_SDCD */
>;
bootph-all;
diff --git a/arch/arm64/include/asm/entry-common.h b/arch/arm64/include/asm/entry-common.h
index cab8cd78f693..20f0a7c7bde1 100644
--- a/arch/arm64/include/asm/entry-common.h
+++ b/arch/arm64/include/asm/entry-common.h
@@ -29,14 +29,19 @@ static __always_inline void arch_exit_to_user_mode_work(struct pt_regs *regs,
static inline bool arch_irqentry_exit_need_resched(void)
{
- /*
- * DAIF.DA are cleared at the start of IRQ/FIQ handling, and when GIC
- * priority masking is used the GIC irqchip driver will clear DAIF.IF
- * using gic_arch_enable_irqs() for normal IRQs. If anything is set in
- * DAIF we must have handled an NMI, so skip preemption.
- */
- if (system_uses_irq_prio_masking() && read_sysreg(daif))
- return false;
+ if (system_uses_irq_prio_masking()) {
+ /*
+ * DAIF.DA are cleared at the start of IRQ/FIQ handling, and when GIC
+ * priority masking is used the GIC irqchip driver will clear DAIF.IF
+ * using gic_arch_enable_irqs() for normal IRQs. If anything is set in
+ * DAIF we must have handled an NMI, so skip preemption.
+ */
+ if (read_sysreg(daif))
+ return false;
+ } else {
+ if (read_sysreg(daif) & (PSR_D_BIT | PSR_A_BIT))
+ return false;
+ }
/*
* Preempting a task from an IRQ means we leave copies of PSTATE
diff --git a/arch/arm64/include/asm/kernel-pgtable.h b/arch/arm64/include/asm/kernel-pgtable.h
index 74a4f738c5f5..229ee7976f69 100644
--- a/arch/arm64/include/asm/kernel-pgtable.h
+++ b/arch/arm64/include/asm/kernel-pgtable.h
@@ -68,7 +68,12 @@
#define KERNEL_SEGMENT_COUNT 5
#if SWAPPER_BLOCK_SIZE > SEGMENT_ALIGN
-#define EARLY_SEGMENT_EXTRA_PAGES (KERNEL_SEGMENT_COUNT + 1)
+/*
+ * KERNEL_SEGMENT_COUNT counts the permanent kernel VMAs. The early mapping
+ * has one additional split, [_text, _stext). Reserve one more page for the
+ * SWAPPER_BLOCK_SIZE-unaligned boundaries.
+ */
+#define EARLY_SEGMENT_EXTRA_PAGES (KERNEL_SEGMENT_COUNT + 2)
/*
* The initial ID map consists of the kernel image, mapped as two separate
* segments, and may appear misaligned wrt the swapper block size. This means
diff --git a/arch/arm64/include/asm/xor.h b/arch/arm64/include/asm/xor.h
index c38e3d017a79..bb7428d4ebc6 100644
--- a/arch/arm64/include/asm/xor.h
+++ b/arch/arm64/include/asm/xor.h
@@ -13,7 +13,7 @@
#ifdef CONFIG_KERNEL_MODE_NEON
-extern struct xor_block_template const xor_block_inner_neon;
+extern struct xor_block_template xor_block_inner_neon __ro_after_init;
static void
xor_neon_2(unsigned long bytes, unsigned long * __restrict p1,
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 32c2dbcc0c64..348197d9b601 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -565,7 +565,7 @@ static const struct arm64_ftr_bits ftr_id_aa64dfr0[] = {
* We can instantiate multiple PMU instances with different levels
* of support.
*/
- S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64DFR0_EL1_PMUVer_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64DFR0_EL1_PMUVer_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_EL1_DebugVer_SHIFT, 4, 0x6),
ARM64_FTR_END,
};
@@ -709,7 +709,7 @@ static const struct arm64_ftr_bits ftr_id_pfr2[] = {
static const struct arm64_ftr_bits ftr_id_dfr0[] = {
/* [31:28] TraceFilt */
- S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_DFR0_EL1_PerfMon_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_DFR0_EL1_PerfMon_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_MProfDbg_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_MMapTrc_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_CopTrc_SHIFT, 4, 0),
diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c
index 239c16e3d02f..c5693a32e49b 100644
--- a/arch/arm64/kernel/machine_kexec.c
+++ b/arch/arm64/kernel/machine_kexec.c
@@ -129,9 +129,6 @@ int machine_kexec_post_load(struct kimage *kimage)
}
/* Create a copy of the linear map */
- trans_pgd = kexec_page_alloc(kimage);
- if (!trans_pgd)
- return -ENOMEM;
rc = trans_pgd_create_copy(&info, &trans_pgd, PAGE_OFFSET, PAGE_END);
if (rc)
return rc;
diff --git a/arch/arm64/kernel/pi/patch-scs.c b/arch/arm64/kernel/pi/patch-scs.c
index dac568e4a54f..3944ad899021 100644
--- a/arch/arm64/kernel/pi/patch-scs.c
+++ b/arch/arm64/kernel/pi/patch-scs.c
@@ -196,9 +196,9 @@ static int scs_handle_fde_frame(const struct eh_frame *frame,
loc += *opcode++ * code_alignment_factor;
loc += (*opcode++ << 8) * code_alignment_factor;
loc += (*opcode++ << 16) * code_alignment_factor;
- loc += (*opcode++ << 24) * code_alignment_factor;
+ loc += ((u64)*opcode++ << 24) * code_alignment_factor;
size -= 4;
- break;
+ break;
case DW_CFA_def_cfa:
case DW_CFA_offset_extended:
diff --git a/arch/arm64/kernel/sys32.c b/arch/arm64/kernel/sys32.c
index 96bcfb907443..12a948f3a504 100644
--- a/arch/arm64/kernel/sys32.c
+++ b/arch/arm64/kernel/sys32.c
@@ -89,7 +89,7 @@ COMPAT_SYSCALL_DEFINE4(aarch32_truncate64, const char __user *, pathname,
COMPAT_SYSCALL_DEFINE4(aarch32_ftruncate64, unsigned int, fd, u32, __pad,
arg_u32p(length))
{
- return ksys_ftruncate(fd, arg_u64(length));
+ return ksys_ftruncate(fd, arg_u64(length), FTRUNCATE_LFS);
}
COMPAT_SYSCALL_DEFINE5(aarch32_readahead, int, fd, u32, __pad,
diff --git a/arch/arm64/lib/insn.c b/arch/arm64/lib/insn.c
index cc5b40917d0d..37ce75f7f1f0 100644
--- a/arch/arm64/lib/insn.c
+++ b/arch/arm64/lib/insn.c
@@ -338,6 +338,8 @@ u32 aarch64_insn_gen_cond_branch_imm(unsigned long pc, unsigned long addr,
long offset;
offset = label_imm_common(pc, addr, SZ_1M);
+ if (offset >= SZ_1M)
+ return AARCH64_BREAK_FAULT;
insn = aarch64_insn_get_bcond_value();
diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
index adf84962d579..524b67c0867e 100644
--- a/arch/arm64/net/bpf_jit_comp.c
+++ b/arch/arm64/net/bpf_jit_comp.c
@@ -18,7 +18,6 @@
#include <asm/asm-extable.h>
#include <asm/byteorder.h>
-#include <asm/cacheflush.h>
#include <asm/cpufeature.h>
#include <asm/debug-monitors.h>
#include <asm/insn.h>
@@ -35,8 +34,8 @@
#define ARENA_VM_START (MAX_BPF_JIT_REG + 5)
#define check_imm(bits, imm) do { \
- if ((((imm) > 0) && ((imm) >> (bits))) || \
- (((imm) < 0) && (~(imm) >> (bits)))) { \
+ if ((((imm) > 0) && ((imm) >> ((bits) - 1))) || \
+ (((imm) < 0) && (~(imm) >> ((bits) - 1)))) { \
pr_info("[%2d] imm=%d(0x%x) out of range\n", \
i, imm, imm); \
return -EINVAL; \
@@ -1961,11 +1960,6 @@ static int validate_ctx(struct jit_ctx *ctx)
return 0;
}
-static inline void bpf_flush_icache(void *start, void *end)
-{
- flush_icache_range((unsigned long)start, (unsigned long)end);
-}
-
static void priv_stack_init_guard(void __percpu *priv_stack_ptr, int alloc_size)
{
int cpu, underflow_idx = (alloc_size - PRIV_STACK_GUARD_SZ) >> 3;
@@ -2204,12 +2198,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
prog = orig_prog;
goto out_off;
}
- /*
- * The instructions have now been copied to the ROX region from
- * where they will execute. Now the data cache has to be cleaned to
- * the PoU and the I-cache has to be invalidated for the VAs.
- */
- bpf_flush_icache(ro_header, ctx.ro_image + ctx.idx);
} else {
jit_data->ctx = ctx;
jit_data->ro_image = ro_image_ptr;
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index a0c0a7a654e9..fe9a787db569 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -60,7 +60,7 @@ SYSCALL_DEFINE4(32_truncate64, const char __user *, path,
SYSCALL_DEFINE4(32_ftruncate64, unsigned long, fd, unsigned long, __dummy,
unsigned long, a2, unsigned long, a3)
{
- return ksys_ftruncate(fd, merge_64(a2, a3));
+ return ksys_ftruncate(fd, merge_64(a2, a3), FTRUNCATE_LFS);
}
SYSCALL_DEFINE5(32_llseek, unsigned int, fd, unsigned int, offset_high,
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
index b2cdbb8a12b1..fcb0d8069139 100644
--- a/arch/parisc/kernel/sys_parisc.c
+++ b/arch/parisc/kernel/sys_parisc.c
@@ -216,7 +216,7 @@ asmlinkage long parisc_truncate64(const char __user * path,
asmlinkage long parisc_ftruncate64(unsigned int fd,
unsigned int high, unsigned int low)
{
- return ksys_ftruncate(fd, (long)high << 32 | low);
+ return ksys_ftruncate(fd, (long)high << 32 | low, FTRUNCATE_LFS);
}
/* stubs for the benefit of the syscall_table since truncate64 and truncate
@@ -227,7 +227,7 @@ asmlinkage long sys_truncate64(const char __user * path, unsigned long length)
}
asmlinkage long sys_ftruncate64(unsigned int fd, unsigned long length)
{
- return ksys_ftruncate(fd, length);
+ return ksys_ftruncate(fd, length, FTRUNCATE_LFS);
}
asmlinkage long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg)
{
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index 1a91762b455d..66a953046a49 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -1313,12 +1313,27 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
{
pmd_t old_pmd;
+ /*
+ * Non-present PMDs can be migration entries or device-private THP
+ * entries. This can happen at 2 places:
+ * - When the address space is being unmapped zap_huge_pmd(), and we
+ * encounter non-present pmds.
+ * - migrate_vma_collect_huge_pmd() could calls this during migration
+ * of device-private pmd entries.
+ */
+ if (!pmd_present(*pmdp)) {
+ old_pmd = READ_ONCE(*pmdp);
+ pmd_clear(pmdp);
+ goto out;
+ }
+
if (radix_enabled()) {
old_pmd = radix__pmdp_huge_get_and_clear(mm, addr, pmdp);
} else {
old_pmd = hash__pmdp_huge_get_and_clear(mm, addr, pmdp);
}
+out:
page_table_check_pmd_clear(mm, addr, old_pmd);
return old_pmd;
diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h
index bd4a6c42a5f3..e02710d6a2e1 100644
--- a/arch/powerpc/include/asm/kexec.h
+++ b/arch/powerpc/include/asm/kexec.h
@@ -66,11 +66,9 @@ void relocate_new_kernel(unsigned long indirection_page, unsigned long reboot_co
unsigned long start_address) __noreturn;
void kexec_copy_flush(struct kimage *image);
-#ifdef CONFIG_KEXEC_FILE
-extern const struct kexec_file_ops kexec_elf64_ops;
+#if defined(CONFIG_KEXEC_FILE) || defined(CONFIG_CRASH_DUMP)
#define ARCH_HAS_KIMAGE_ARCH
-
struct kimage_arch {
struct crash_mem *exclude_ranges;
@@ -78,6 +76,10 @@ struct kimage_arch {
void *backup_buf;
void *fdt;
};
+#endif
+
+#ifdef CONFIG_KEXEC_FILE
+extern const struct kexec_file_ops kexec_elf64_ops;
char *setup_kdump_cmdline(struct kimage *image, char *cmdline,
unsigned long cmdline_len);
@@ -145,6 +147,10 @@ int arch_crash_hotplug_support(struct kimage *image, unsigned long kexec_flags);
unsigned int arch_crash_get_elfcorehdr_size(void);
#define crash_get_elfcorehdr_size arch_crash_get_elfcorehdr_size
+
+int machine_kexec_post_load(struct kimage *image);
+#define machine_kexec_post_load machine_kexec_post_load
+
#endif /* CONFIG_CRASH_HOTPLUG */
extern int crashing_cpu;
@@ -159,6 +165,8 @@ extern void default_machine_crash_shutdown(struct pt_regs *regs);
extern void crash_kexec_prepare(void);
extern void crash_kexec_secondary(struct pt_regs *regs);
+extern void sync_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr,
+ bool phdr_to_kimage);
static inline bool kdump_in_progress(void)
{
return crashing_cpu >= 0;
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index d451a8229223..03fa487f2614 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -101,7 +101,7 @@ PPC32_SYSCALL_DEFINE4(ppc_ftruncate64,
unsigned int, fd, u32, reg4,
unsigned long, len1, unsigned long, len2)
{
- return ksys_ftruncate(fd, merge_64(len1, len2));
+ return ksys_ftruncate(fd, merge_64(len1, len2), FTRUNCATE_LFS);
}
PPC32_SYSCALL_DEFINE6(ppc32_fadvise64,
diff --git a/arch/powerpc/kexec/crash.c b/arch/powerpc/kexec/crash.c
index a325c1c02f96..e6539f213b3d 100644
--- a/arch/powerpc/kexec/crash.c
+++ b/arch/powerpc/kexec/crash.c
@@ -27,6 +27,7 @@
#include <asm/debug.h>
#include <asm/interrupt.h>
#include <asm/kexec_ranges.h>
+#include <asm/crashdump-ppc64.h>
/*
* The primary CPU waits a while for all secondary CPUs to enter. This is to
@@ -399,7 +400,68 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
ppc_md.kexec_cpu_down(1, 0);
}
+#ifdef CONFIG_CRASH_DUMP
+/**
+ * sync_backup_region_phdr - synchronize backup region offset between
+ * kexec image and ELF core header.
+ * @image: Kexec image.
+ * @ehdr: ELF core header.
+ * @phdr_to_kimage: If true, read the offset from the ELF program header
+ * and update the kimage backup region. If false, update
+ * the ELF program header offset from the kimage backup
+ * region.
+ *
+ * Note: During kexec_load, this is called with phdr_to_kimage = true. For
+ * kexec_file_load and ELF core header recreation during memory hotplug
+ * events, it is called with phdr_to_kimage = false.
+ *
+ * Returns nothing.
+ */
+void sync_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr, bool phdr_to_kimage)
+{
+ Elf64_Phdr *phdr;
+ unsigned int i;
+
+ phdr = (Elf64_Phdr *)(ehdr + 1);
+ for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
+ if (phdr->p_paddr == BACKUP_SRC_START) {
+ if (phdr_to_kimage)
+ image->arch.backup_start = phdr->p_offset;
+ else
+ phdr->p_offset = image->arch.backup_start;
+
+ kexec_dprintk("Backup region offset updated to 0x%lx\n",
+ image->arch.backup_start);
+ return;
+ }
+ }
+}
+#endif /* CONFIG_CRASH_DUMP */
+
#ifdef CONFIG_CRASH_HOTPLUG
+
+int machine_kexec_post_load(struct kimage *image)
+{
+ int i;
+ unsigned long mem;
+ unsigned char *ptr;
+
+ if (image->type != KEXEC_TYPE_CRASH)
+ return 0;
+
+ if (image->file_mode)
+ return 0;
+
+ for (i = 0; i < image->nr_segments; i++) {
+ mem = image->segment[i].mem;
+ ptr = (char *)__va(mem);
+
+ if (ptr && memcmp(ptr, ELFMAG, SELFMAG) == 0)
+ sync_backup_region_phdr(image, (Elf64_Ehdr *) ptr, true);
+ }
+ return 0;
+}
+
#undef pr_fmt
#define pr_fmt(fmt) "crash hp: " fmt
@@ -474,6 +536,8 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify *
goto out;
}
+ sync_backup_region_phdr(image, (Elf64_Ehdr *) elfbuf, false);
+
ptr = __va(mem);
if (ptr) {
/* Temporarily invalidate the crash image while it is replaced */
diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c
index 5f6d50e4c3d4..8c72e12ea44e 100644
--- a/arch/powerpc/kexec/file_load_64.c
+++ b/arch/powerpc/kexec/file_load_64.c
@@ -374,33 +374,6 @@ static int load_backup_segment(struct kimage *image, struct kexec_buf *kbuf)
return 0;
}
-/**
- * update_backup_region_phdr - Update backup region's offset for the core to
- * export the region appropriately.
- * @image: Kexec image.
- * @ehdr: ELF core header.
- *
- * Assumes an exclusive program header is setup for the backup region
- * in the ELF headers
- *
- * Returns nothing.
- */
-static void update_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr)
-{
- Elf64_Phdr *phdr;
- unsigned int i;
-
- phdr = (Elf64_Phdr *)(ehdr + 1);
- for (i = 0; i < ehdr->e_phnum; i++) {
- if (phdr->p_paddr == BACKUP_SRC_START) {
- phdr->p_offset = image->arch.backup_start;
- kexec_dprintk("Backup region offset updated to 0x%lx\n",
- image->arch.backup_start);
- return;
- }
- }
-}
-
static unsigned int kdump_extra_elfcorehdr_size(struct crash_mem *cmem)
{
#if defined(CONFIG_CRASH_HOTPLUG) && defined(CONFIG_MEMORY_HOTPLUG)
@@ -445,7 +418,7 @@ static int load_elfcorehdr_segment(struct kimage *image, struct kexec_buf *kbuf)
}
/* Fix the offset for backup region in the ELF header */
- update_backup_region_phdr(image, headers);
+ sync_backup_region_phdr(image, headers, false);
kbuf->buffer = headers;
kbuf->mem = KEXEC_BUF_MEM_UNKNOWN;
diff --git a/arch/powerpc/mm/book3s64/pgtable.c b/arch/powerpc/mm/book3s64/pgtable.c
index 4b09c04654a8..42c7906d0e43 100644
--- a/arch/powerpc/mm/book3s64/pgtable.c
+++ b/arch/powerpc/mm/book3s64/pgtable.c
@@ -209,16 +209,21 @@ pmd_t pmdp_huge_get_and_clear_full(struct vm_area_struct *vma,
unsigned long addr, pmd_t *pmdp, int full)
{
pmd_t pmd;
+ bool was_present = pmd_present(*pmdp);
+
VM_BUG_ON(addr & ~HPAGE_PMD_MASK);
- VM_BUG_ON((pmd_present(*pmdp) && !pmd_trans_huge(*pmdp)) ||
- !pmd_present(*pmdp));
+ VM_BUG_ON(was_present && !pmd_trans_huge(*pmdp));
+ /*
+ * Check pmdp_huge_get_and_clear() for non-present pmd case.
+ */
pmd = pmdp_huge_get_and_clear(vma->vm_mm, addr, pmdp);
/*
* if it not a fullmm flush, then we can possibly end up converting
* this PMD pte entry to a regular level 0 PTE by a parallel page fault.
- * Make sure we flush the tlb in this case.
+ * Make sure we flush the tlb in this case. TLB flush not needed for
+ * non-present case.
*/
- if (!full)
+ if (was_present && !full)
flush_pmd_tlb_range(vma, addr, addr + HPAGE_PMD_SIZE);
return pmd;
}
diff --git a/arch/powerpc/mm/pgtable-frag.c b/arch/powerpc/mm/pgtable-frag.c
index 77e55eac16e4..ae742564a3d5 100644
--- a/arch/powerpc/mm/pgtable-frag.c
+++ b/arch/powerpc/mm/pgtable-frag.c
@@ -25,6 +25,7 @@ void pte_frag_destroy(void *pte_frag)
count = ((unsigned long)pte_frag & ~PAGE_MASK) >> PTE_FRAG_SIZE_SHIFT;
/* We allow PTE_FRAG_NR fragments from a PTE page */
if (atomic_sub_and_test(PTE_FRAG_NR - count, &ptdesc->pt_frag_refcount)) {
+ folio_clear_active(ptdesc_folio(ptdesc));
pagetable_dtor(ptdesc);
pagetable_free(ptdesc);
}
diff --git a/arch/powerpc/platforms/44x/warp.c b/arch/powerpc/platforms/44x/warp.c
index a5001d32f978..6f674f86dc85 100644
--- a/arch/powerpc/platforms/44x/warp.c
+++ b/arch/powerpc/platforms/44x/warp.c
@@ -293,6 +293,8 @@ static int pika_dtm_thread(void __iomem *fpga)
schedule_timeout(HZ);
}
+ put_device(&client->dev);
+
return 0;
}
diff --git a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts b/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
index 5971605754b3..48c034736aa5 100644
--- a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
+++ b/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
@@ -81,8 +81,6 @@ usb3_hub_5v: usb3-hub-5v {
};
&combo_phy {
- pinctrl-names = "default";
- pinctrl-0 = <&pcie0_3_cfg>;
status = "okay";
};
@@ -305,6 +303,7 @@ &pcie1_phy {
&pcie1_port {
phys = <&pcie1_phy>;
+ vpcie3v3-supply = <&pcie_vcc_3v3>;
};
&pcie1 {
@@ -320,6 +319,7 @@ &pcie2_phy {
&pcie2_port {
phys = <&pcie2_phy>;
+ vpcie3v3-supply = <&pcie_vcc_3v3>;
};
&pcie2 {
diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h
index 632ced07bca4..da0271790244 100644
--- a/arch/riscv/net/bpf_jit.h
+++ b/arch/riscv/net/bpf_jit.h
@@ -11,7 +11,6 @@
#include <linux/bpf.h>
#include <linux/filter.h>
-#include <asm/cacheflush.h>
/* verify runtime detection extension status */
#define rv_ext_enabled(ext) \
@@ -105,11 +104,6 @@ static inline void bpf_fill_ill_insns(void *area, unsigned int size)
memset(area, 0, size);
}
-static inline void bpf_flush_icache(void *start, void *end)
-{
- flush_icache_range((unsigned long)start, (unsigned long)end);
-}
-
/* Emit a 4-byte riscv instruction. */
static inline void emit(const u32 insn, struct rv_jit_context *ctx)
{
diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c
index b3581e926436..f7fd4afc3ca3 100644
--- a/arch/riscv/net/bpf_jit_core.c
+++ b/arch/riscv/net/bpf_jit_core.c
@@ -183,13 +183,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
prog = orig_prog;
goto out_offset;
}
- /*
- * The instructions have now been copied to the ROX region from
- * where they will execute.
- * Write any modified data cache blocks out to memory and
- * invalidate the corresponding blocks in the instruction cache.
- */
- bpf_flush_icache(jit_data->ro_header, ctx->ro_insns + ctx->ninsns);
for (i = 0; i < prog->len; i++)
ctx->offset[i] = ninsns_rvoff(ctx->offset[i]);
bpf_prog_fill_jited_linfo(prog, ctx->offset);
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 7cb8ce833b62..f48f25c7dc8f 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -3307,8 +3307,7 @@ static void aen_host_forward(unsigned long si)
struct zpci_gaite *gaite;
struct kvm *kvm;
- gaite = (struct zpci_gaite *)aift->gait +
- (si * sizeof(struct zpci_gaite));
+ gaite = aift->gait + si;
if (gaite->count == 0)
return;
if (gaite->aisb != 0)
diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
index 86d93e8dddae..eed45af1a92d 100644
--- a/arch/s390/kvm/pci.c
+++ b/arch/s390/kvm/pci.c
@@ -290,8 +290,7 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
phys_to_virt(fib->fmt0.aibv));
spin_lock_irq(&aift->gait_lock);
- gaite = (struct zpci_gaite *)aift->gait + (zdev->aisb *
- sizeof(struct zpci_gaite));
+ gaite = aift->gait + zdev->aisb;
/* If assist not requested, host will get all alerts */
if (assist)
@@ -357,8 +356,7 @@ static int kvm_s390_pci_aif_disable(struct zpci_dev *zdev, bool force)
if (zdev->kzdev->fib.fmt0.aibv == 0)
goto out;
spin_lock_irq(&aift->gait_lock);
- gaite = (struct zpci_gaite *)aift->gait + (zdev->aisb *
- sizeof(struct zpci_gaite));
+ gaite = aift->gait + zdev->aisb;
isc = gaite->gisc;
gaite->count--;
if (gaite->count == 0) {
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 191cc53caead..028aeb9c48d6 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -438,7 +438,7 @@ void do_secure_storage_access(struct pt_regs *regs)
panic("Unexpected PGM 0x3d with TEID bit 61=0");
}
if (is_kernel_fault(regs)) {
- folio = phys_to_folio(addr);
+ folio = virt_to_folio((void *)addr);
if (unlikely(!folio_try_get(folio)))
return;
rc = uv_convert_from_secure(folio_to_phys(folio));
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
index bf92964246eb..10ab247e1994 100644
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -830,25 +830,34 @@ static int bpf_jit_probe_post(struct bpf_jit *jit, struct bpf_prog *fp,
}
/*
- * Sign-extend the register if necessary
+ * Sign- or zero-extend the register if necessary
*/
-static int sign_extend(struct bpf_jit *jit, int r, u8 size, u8 flags)
+static int sign_zero_extend(struct bpf_jit *jit, int r, u8 size, u8 flags)
{
- if (!(flags & BTF_FMODEL_SIGNED_ARG))
- return 0;
-
switch (size) {
case 1:
- /* lgbr %r,%r */
- EMIT4(0xb9060000, r, r);
+ if (flags & BTF_FMODEL_SIGNED_ARG)
+ /* lgbr %r,%r */
+ EMIT4(0xb9060000, r, r);
+ else
+ /* llgcr %r,%r */
+ EMIT4(0xb9840000, r, r);
return 0;
case 2:
- /* lghr %r,%r */
- EMIT4(0xb9070000, r, r);
+ if (flags & BTF_FMODEL_SIGNED_ARG)
+ /* lghr %r,%r */
+ EMIT4(0xb9070000, r, r);
+ else
+ /* llghr %r,%r */
+ EMIT4(0xb9850000, r, r);
return 0;
case 4:
- /* lgfr %r,%r */
- EMIT4(0xb9140000, r, r);
+ if (flags & BTF_FMODEL_SIGNED_ARG)
+ /* lgfr %r,%r */
+ EMIT4(0xb9140000, r, r);
+ else
+ /* llgfr %r,%r */
+ EMIT4(0xb9160000, r, r);
return 0;
case 8:
return 0;
@@ -1798,9 +1807,9 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
return -1;
for (j = 0; j < m->nr_args; j++) {
- if (sign_extend(jit, BPF_REG_1 + j,
- m->arg_size[j],
- m->arg_flags[j]))
+ if (sign_zero_extend(jit, BPF_REG_1 + j,
+ m->arg_size[j],
+ m->arg_flags[j]))
return -1;
}
}
@@ -2555,7 +2564,7 @@ static int invoke_bpf_prog(struct bpf_tramp_jit *tjit,
EMIT6_PCREL_RILB_PTR(0xc0050000, REG_14, p->bpf_func);
/* stg %r2,retval_off(%r15) */
if (save_ret) {
- if (sign_extend(jit, REG_2, m->ret_size, m->ret_flags))
+ if (sign_zero_extend(jit, REG_2, m->ret_size, m->ret_flags))
return -1;
EMIT6_DISP_LH(0xe3000000, 0x0024, REG_2, REG_0, REG_15,
tjit->retval_off);
diff --git a/arch/sh/include/cpu-sh3/cpu/dac.h b/arch/sh/include/cpu-sh3/cpu/dac.h
index fd02331608a8..323ec8570bcd 100644
--- a/arch/sh/include/cpu-sh3/cpu/dac.h
+++ b/arch/sh/include/cpu-sh3/cpu/dac.h
@@ -2,6 +2,8 @@
#ifndef __ASM_CPU_SH3_DAC_H
#define __ASM_CPU_SH3_DAC_H
+#include <linux/io.h>
+
/*
* Copyright (C) 2003 Andriy Skulysh
*/
diff --git a/arch/sparc/kernel/sys_sparc32.c b/arch/sparc/kernel/sys_sparc32.c
index f84a02ab6bf9..04432b82b9e3 100644
--- a/arch/sparc/kernel/sys_sparc32.c
+++ b/arch/sparc/kernel/sys_sparc32.c
@@ -58,7 +58,7 @@ COMPAT_SYSCALL_DEFINE3(truncate64, const char __user *, path, u32, high, u32, lo
COMPAT_SYSCALL_DEFINE3(ftruncate64, unsigned int, fd, u32, high, u32, low)
{
- return ksys_ftruncate(fd, ((u64)high << 32) | low);
+ return ksys_ftruncate(fd, ((u64)high << 32) | low, FTRUNCATE_LFS);
}
static int cp_compat_stat64(struct kstat *stat,
diff --git a/arch/sparc/vdso/Makefile b/arch/sparc/vdso/Makefile
index 683b2d408224..400529acd1c1 100644
--- a/arch/sparc/vdso/Makefile
+++ b/arch/sparc/vdso/Makefile
@@ -104,4 +104,4 @@ quiet_cmd_vdso = VDSO $@
$(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \
-T $(filter %.lds,$^) $(filter %.o,$^)
-VDSO_LDFLAGS = -shared --hash-style=both --build-id=sha1 -Bsymbolic --no-undefined
+VDSO_LDFLAGS = -shared --hash-style=both --build-id=sha1 -Bsymbolic --no-undefined -z noexecstack
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index 39608cccf2c6..5386ab2d0da5 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -165,6 +165,7 @@ int um_tlb_sync(struct mm_struct *mm)
unsigned long addr, next;
int ret = 0;
+ guard(spinlock_irqsave)(&mm->page_table_lock);
guard(spinlock_irqsave)(&mm->context.sync_tlb_lock);
if (mm->context.sync_tlb_range_to == 0)
diff --git a/arch/x86/Makefile.um b/arch/x86/Makefile.um
index c86cbd9cbba3..19c13afa474e 100644
--- a/arch/x86/Makefile.um
+++ b/arch/x86/Makefile.um
@@ -60,4 +60,6 @@ ELF_FORMAT := elf64-x86-64
LINK-$(CONFIG_LD_SCRIPT_DYN_RPATH) += -Wl,-rpath,/lib64
LINK-y += -m64
+vdso-install-y += arch/x86/um/vdso/vdso.so.dbg
+
endif
diff --git a/arch/x86/coco/tdx/debug.c b/arch/x86/coco/tdx/debug.c
index cef847c8bb67..28990c2ab0a1 100644
--- a/arch/x86/coco/tdx/debug.c
+++ b/arch/x86/coco/tdx/debug.c
@@ -17,7 +17,7 @@ static __initdata const char *tdx_attributes[] = {
DEF_TDX_ATTR_NAME(ICSSD),
DEF_TDX_ATTR_NAME(LASS),
DEF_TDX_ATTR_NAME(SEPT_VE_DISABLE),
- DEF_TDX_ATTR_NAME(MIGRTABLE),
+ DEF_TDX_ATTR_NAME(MIGRATABLE),
DEF_TDX_ATTR_NAME(PKS),
DEF_TDX_ATTR_NAME(KL),
DEF_TDX_ATTR_NAME(TPA),
diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c
index aca89f23d2e0..7b8eea1d75c1 100644
--- a/arch/x86/events/amd/ibs.c
+++ b/arch/x86/events/amd/ibs.c
@@ -313,6 +313,9 @@ static int perf_ibs_init(struct perf_event *event)
if (ret)
return ret;
+ if (perf_allow_kernel())
+ hwc->flags |= PERF_X86_EVENT_UNPRIVILEGED;
+
if (hwc->sample_period) {
if (config & perf_ibs->cnt_mask)
/* raw max_cnt may not be set */
@@ -1214,12 +1217,10 @@ static void perf_ibs_phyaddr_clear(struct perf_ibs *perf_ibs,
struct perf_ibs_data *ibs_data)
{
if (perf_ibs == &perf_ibs_op) {
- ibs_data->regs[ibs_op_msr_idx(MSR_AMD64_IBSOPDATA3)] &= ~(1ULL << 18);
ibs_data->regs[ibs_op_msr_idx(MSR_AMD64_IBSDCPHYSAD)] = 0;
return;
}
- ibs_data->regs[ibs_fetch_msr_idx(MSR_AMD64_IBSFETCHCTL)] &= ~(1ULL << 52);
ibs_data->regs[ibs_fetch_msr_idx(MSR_AMD64_IBSFETCHPHYSAD)] = 0;
}
@@ -1293,8 +1294,10 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
* within [128, 2048] range.
*/
if (!op_data3.ld_op || !op_data3.dc_miss ||
- op_data3.dc_miss_lat <= (event->attr.config1 & 0xFFF))
+ op_data3.dc_miss_lat <= (event->attr.config1 & 0xFFF)) {
+ throttle = perf_event_account_interrupt(event);
goto out;
+ }
}
/*
@@ -1326,8 +1329,10 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
regs.flags &= ~PERF_EFLAGS_EXACT;
} else {
/* Workaround for erratum #1197 */
- if (perf_ibs->fetch_ignore_if_zero_rip && !(ibs_data.regs[1]))
+ if (perf_ibs->fetch_ignore_if_zero_rip && !(ibs_data.regs[1])) {
+ throttle = perf_event_account_interrupt(event);
goto out;
+ }
set_linear_ip(®s, ibs_data.regs[1]);
regs.flags |= PERF_EFLAGS_EXACT;
@@ -1344,7 +1349,7 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
* unprivileged users.
*/
if ((event->attr.sample_type & PERF_SAMPLE_RAW) &&
- perf_allow_kernel()) {
+ (hwc->flags & PERF_X86_EVENT_UNPRIVILEGED)) {
perf_ibs_phyaddr_clear(perf_ibs, &ibs_data);
}
diff --git a/arch/x86/events/perf_event_flags.h b/arch/x86/events/perf_event_flags.h
index 70078334e4a3..47f84ee8f540 100644
--- a/arch/x86/events/perf_event_flags.h
+++ b/arch/x86/events/perf_event_flags.h
@@ -23,3 +23,4 @@ PERF_ARCH(PEBS_LAT_HYBRID, 0x0020000) /* ld and st lat for hybrid */
PERF_ARCH(NEEDS_BRANCH_STACK, 0x0040000) /* require branch stack setup */
PERF_ARCH(BRANCH_COUNTERS, 0x0080000) /* logs the counters in the extra space of each branch */
PERF_ARCH(ACR, 0x0100000) /* Auto counter reload */
+PERF_ARCH(UNPRIVILEGED, 0x0200000) /* Unprivileged event (wrt perf_allow_kernel()) */
diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h
index 462754b0bf8a..6f25de05ed58 100644
--- a/arch/x86/include/asm/irqflags.h
+++ b/arch/x86/include/asm/irqflags.h
@@ -96,11 +96,11 @@ static __always_inline void halt(void)
native_halt();
}
#endif /* __ASSEMBLER__ */
+#else
+#include <asm/paravirt.h>
#endif /* CONFIG_PARAVIRT */
-#ifdef CONFIG_PARAVIRT_XXL
-#include <asm/paravirt.h>
-#else
+#ifndef CONFIG_PARAVIRT_XXL
#ifndef __ASSEMBLER__
#include <linux/types.h>
diff --git a/arch/x86/include/asm/shared/tdx.h b/arch/x86/include/asm/shared/tdx.h
index 8bc074c8d7c6..11f3cf30b1ac 100644
--- a/arch/x86/include/asm/shared/tdx.h
+++ b/arch/x86/include/asm/shared/tdx.h
@@ -35,8 +35,8 @@
#define TDX_ATTR_LASS BIT_ULL(TDX_ATTR_LASS_BIT)
#define TDX_ATTR_SEPT_VE_DISABLE_BIT 28
#define TDX_ATTR_SEPT_VE_DISABLE BIT_ULL(TDX_ATTR_SEPT_VE_DISABLE_BIT)
-#define TDX_ATTR_MIGRTABLE_BIT 29
-#define TDX_ATTR_MIGRTABLE BIT_ULL(TDX_ATTR_MIGRTABLE_BIT)
+#define TDX_ATTR_MIGRATABLE_BIT 29
+#define TDX_ATTR_MIGRATABLE BIT_ULL(TDX_ATTR_MIGRATABLE_BIT)
#define TDX_ATTR_PKS_BIT 30
#define TDX_ATTR_PKS BIT_ULL(TDX_ATTR_PKS_BIT)
#define TDX_ATTR_KL_BIT 31
diff --git a/arch/x86/include/asm/vdso.h b/arch/x86/include/asm/vdso.h
index e8afbe9faa5b..f2d49212ae90 100644
--- a/arch/x86/include/asm/vdso.h
+++ b/arch/x86/include/asm/vdso.h
@@ -18,7 +18,6 @@ struct vdso_image {
unsigned long extable_base, extable_len;
const void *extable;
- long sym_VDSO32_NOTE_MASK;
long sym___kernel_sigreturn;
long sym___kernel_rt_sigreturn;
long sym___kernel_vsyscall;
diff --git a/arch/x86/kernel/acpi/cppc.c b/arch/x86/kernel/acpi/cppc.c
index d7c8ef1e354d..be4c5e9e5ff6 100644
--- a/arch/x86/kernel/acpi/cppc.c
+++ b/arch/x86/kernel/acpi/cppc.c
@@ -88,19 +88,19 @@ static void amd_set_max_freq_ratio(void)
rc = cppc_get_perf_caps(0, &perf_caps);
if (rc) {
- pr_warn("Could not retrieve perf counters (%d)\n", rc);
+ pr_debug("Could not retrieve perf counters (%d)\n", rc);
return;
}
rc = amd_get_boost_ratio_numerator(0, &numerator);
if (rc) {
- pr_warn("Could not retrieve highest performance (%d)\n", rc);
+ pr_debug("Could not retrieve highest performance (%d)\n", rc);
return;
}
nominal_perf = perf_caps.nominal_perf;
if (!nominal_perf) {
- pr_warn("Could not retrieve nominal performance\n");
+ pr_debug("Could not retrieve nominal performance\n");
return;
}
diff --git a/arch/x86/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S
index 4ffba68dc57b..eaeb77464c06 100644
--- a/arch/x86/kernel/relocate_kernel_64.S
+++ b/arch/x86/kernel/relocate_kernel_64.S
@@ -136,6 +136,14 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
* %r13 original CR4 when relocate_kernel() was invoked
*/
+ /*
+ * Set return address to 0 if not preserving context. The purgatory
+ * shipped in kexec-tools will unconditionally look for the return
+ * address on the stack and set a kexec_jump_back_entry= command
+ * line option if it's non-zero. There's no other way that it can
+ * tell a preserve-context (kjump) kexec from a normal one.
+ */
+ pushq $0
/* store the start address on the stack */
pushq %rdx
diff --git a/arch/x86/kernel/sys_ia32.c b/arch/x86/kernel/sys_ia32.c
index 6cf65397d225..610a1c2f4519 100644
--- a/arch/x86/kernel/sys_ia32.c
+++ b/arch/x86/kernel/sys_ia32.c
@@ -61,7 +61,8 @@ SYSCALL_DEFINE3(ia32_truncate64, const char __user *, filename,
SYSCALL_DEFINE3(ia32_ftruncate64, unsigned int, fd,
unsigned long, offset_low, unsigned long, offset_high)
{
- return ksys_ftruncate(fd, ((loff_t) offset_high << 32) | offset_low);
+ return ksys_ftruncate(fd, ((loff_t) offset_high << 32) | offset_low,
+ FTRUNCATE_LFS);
}
/* warning: next two assume little endian */
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index c8e292e9a24d..292f1dded78f 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -4469,7 +4469,7 @@ static const struct opcode opcode_map_0f_38[256] = {
X16(N), X16(N),
/* 0x20 - 0x2f */
X8(N),
- X2(N), GP(SrcReg | DstMem | ModRM | Mov | Aligned, &pfx_0f_e7_0f_38_2a), N, N, N, N, N,
+ X2(N), GP(SrcMem | DstReg | ModRM | Mov | Aligned, &pfx_0f_e7_0f_38_2a), N, N, N, N, N,
/* 0x30 - 0x7f */
X16(N), X16(N), X16(N), X16(N), X16(N),
/* 0x80 - 0xef */
diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h
index e7fdbe9efc90..0db25bba17f6 100644
--- a/arch/x86/kvm/trace.h
+++ b/arch/x86/kvm/trace.h
@@ -154,7 +154,7 @@ TRACE_EVENT(kvm_xen_hypercall,
__entry->a2 = a2;
__entry->a3 = a3;
__entry->a4 = a4;
- __entry->a4 = a5;
+ __entry->a5 = a5;
),
TP_printk("cpl %d nr 0x%lx a0 0x%lx a1 0x%lx a2 0x%lx a3 0x%lx a4 0x%lx a5 %lx",
diff --git a/arch/x86/tools/vdso2c.c b/arch/x86/tools/vdso2c.c
index f84e8f8fa5fe..b8a555763f43 100644
--- a/arch/x86/tools/vdso2c.c
+++ b/arch/x86/tools/vdso2c.c
@@ -75,7 +75,6 @@ struct vdso_sym {
};
struct vdso_sym required_syms[] = {
- {"VDSO32_NOTE_MASK", true},
{"__kernel_vsyscall", true},
{"__kernel_sigreturn", true},
{"__kernel_rt_sigreturn", true},
diff --git a/arch/x86/um/vdso/Makefile b/arch/x86/um/vdso/Makefile
index 8a7c8b37cb6e..7664cbedbe30 100644
--- a/arch/x86/um/vdso/Makefile
+++ b/arch/x86/um/vdso/Makefile
@@ -3,8 +3,6 @@
# Building vDSO images for x86.
#
-vdso-install-y += vdso.so
-
# files to link into the vdso
vobjs-y := vdso-note.o um_vdso.o
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index b70096497d38..554c87bb4a86 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -24,6 +24,7 @@
#include <linux/backing-dev.h>
#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/wait_bit.h>
#include <linux/atomic.h>
#include <linux/ctype.h>
#include <linux/resume_user_mode.h>
@@ -611,6 +612,8 @@ static void blkg_destroy_all(struct gendisk *disk)
q->root_blkg = NULL;
spin_unlock_irq(&q->queue_lock);
+
+ wake_up_var(&q->root_blkg);
}
static void blkg_iostat_set(struct blkg_iostat *dst, struct blkg_iostat *src)
@@ -1498,6 +1501,18 @@ int blkcg_init_disk(struct gendisk *disk)
struct blkcg_gq *new_blkg, *blkg;
bool preloaded;
+ /*
+ * If the queue is shared across disk rebind (e.g., SCSI), the
+ * previous disk's blkcg state is cleaned up asynchronously via
+ * disk_release() -> blkcg_exit_disk(). Wait for that cleanup to
+ * finish (indicated by root_blkg becoming NULL) before setting up
+ * new blkcg state. Otherwise, we may overwrite q->root_blkg while
+ * the old one is still alive, and radix_tree_insert() in
+ * blkg_create() will fail with -EEXIST because the old entries
+ * still occupy the same queue id slot in blkcg->blkg_tree.
+ */
+ wait_var_event(&q->root_blkg, !READ_ONCE(q->root_blkg));
+
new_blkg = blkg_alloc(&blkcg_root, disk, GFP_KERNEL);
if (!new_blkg)
return -ENOMEM;
@@ -2022,6 +2037,7 @@ void blkcg_maybe_throttle_current(void)
return;
out:
rcu_read_unlock();
+ put_disk(disk);
}
/**
diff --git a/block/blk-wbt.c b/block/blk-wbt.c
index 33006edfccd4..dcc2438ca16d 100644
--- a/block/blk-wbt.c
+++ b/block/blk-wbt.c
@@ -782,10 +782,11 @@ void wbt_init_enable_default(struct gendisk *disk)
return;
rwb = wbt_alloc();
- if (WARN_ON_ONCE(!rwb))
+ if (!rwb)
return;
- if (WARN_ON_ONCE(wbt_init(disk, rwb))) {
+ if (wbt_init(disk, rwb)) {
+ pr_warn("%s: failed to enable wbt\n", disk->disk_name);
wbt_free(rwb);
return;
}
diff --git a/block/blk-zoned.c b/block/blk-zoned.c
index 7aae3c236cad..a4d82342e37a 100644
--- a/block/blk-zoned.c
+++ b/block/blk-zoned.c
@@ -1877,6 +1877,7 @@ static int disk_revalidate_zone_resources(struct gendisk *disk,
{
struct queue_limits *lim = &disk->queue->limits;
unsigned int pool_size;
+ int ret = 0;
args->disk = disk;
args->nr_zones =
@@ -1899,10 +1900,13 @@ static int disk_revalidate_zone_resources(struct gendisk *disk,
pool_size =
min(BLK_ZONE_WPLUG_DEFAULT_POOL_SIZE, args->nr_zones);
- if (!disk->zone_wplugs_hash)
- return disk_alloc_zone_resources(disk, pool_size);
+ if (!disk->zone_wplugs_hash) {
+ ret = disk_alloc_zone_resources(disk, pool_size);
+ if (ret)
+ kfree(args->zones_cond);
+ }
- return 0;
+ return ret;
}
/*
@@ -1934,6 +1938,7 @@ static int disk_update_zone_resources(struct gendisk *disk,
disk->zone_capacity = args->zone_capacity;
disk->last_zone_capacity = args->last_zone_capacity;
disk_set_zones_cond_array(disk, args->zones_cond);
+ args->zones_cond = NULL;
/*
* Some devices can advertise zone resource limits that are larger than
@@ -2216,21 +2221,30 @@ int blk_revalidate_disk_zones(struct gendisk *disk)
}
memalloc_noio_restore(noio_flag);
+ if (ret <= 0)
+ goto free_resources;
+
/*
* If zones where reported, make sure that the entire disk capacity
* has been checked.
*/
- if (ret > 0 && args.sector != capacity) {
+ if (args.sector != capacity) {
pr_warn("%s: Missing zones from sector %llu\n",
disk->disk_name, args.sector);
ret = -ENODEV;
+ goto free_resources;
}
- if (ret > 0)
- return disk_update_zone_resources(disk, &args);
+ ret = disk_update_zone_resources(disk, &args);
+ if (ret)
+ goto free_resources;
+
+ return 0;
+free_resources:
pr_warn("%s: failed to revalidate zones\n", disk->disk_name);
+ kfree(args.zones_cond);
memflags = blk_mq_freeze_queue(q);
disk_free_zone_resources(disk);
blk_mq_unfreeze_queue(q, memflags);
diff --git a/block/disk-events.c b/block/disk-events.c
index 9f9f9f8a2d6b..074731ecc3d2 100644
--- a/block/disk-events.c
+++ b/block/disk-events.c
@@ -290,13 +290,14 @@ EXPORT_SYMBOL(disk_check_media_change);
* Should be called when the media changes for @disk. Generates a uevent
* and attempts to free all dentries and inodes and invalidates all block
* device page cache entries in that case.
+ *
+ * Callers that need a partition re-scan should arrange for one explicitly.
*/
void disk_force_media_change(struct gendisk *disk)
{
disk_event_uevent(disk, DISK_EVENT_MEDIA_CHANGE);
inc_diskseq(disk);
bdev_mark_dead(disk->part0, true);
- set_bit(GD_NEED_PART_SCAN, &disk->state);
}
EXPORT_SYMBOL_GPL(disk_force_media_change);
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index dd0e5be4d8c0..53d265591363 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -586,6 +586,8 @@ static int af_alg_cmsg_send(struct msghdr *msg, struct af_alg_control *con)
if (cmsg->cmsg_len < CMSG_LEN(sizeof(u32)))
return -EINVAL;
con->aead_assoclen = *(u32 *)CMSG_DATA(cmsg);
+ if (con->aead_assoclen >= 0x80000000u)
+ return -EINVAL;
break;
default:
diff --git a/crypto/jitterentropy-kcapi.c b/crypto/jitterentropy-kcapi.c
index 7c880cf34c52..5edc6d285aa1 100644
--- a/crypto/jitterentropy-kcapi.c
+++ b/crypto/jitterentropy-kcapi.c
@@ -42,6 +42,7 @@
#include <linux/fips.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <crypto/internal/rng.h>
@@ -193,7 +194,7 @@ int jent_read_random_block(void *hash_state, char *dst, unsigned int dst_len)
***************************************************************************/
struct jitterentropy {
- spinlock_t jent_lock;
+ struct mutex jent_lock;
struct rand_data *entropy_collector;
struct crypto_shash *tfm;
struct shash_desc *sdesc;
@@ -203,7 +204,7 @@ static void jent_kcapi_cleanup(struct crypto_tfm *tfm)
{
struct jitterentropy *rng = crypto_tfm_ctx(tfm);
- spin_lock(&rng->jent_lock);
+ mutex_lock(&rng->jent_lock);
if (rng->sdesc) {
shash_desc_zero(rng->sdesc);
@@ -218,7 +219,7 @@ static void jent_kcapi_cleanup(struct crypto_tfm *tfm)
if (rng->entropy_collector)
jent_entropy_collector_free(rng->entropy_collector);
rng->entropy_collector = NULL;
- spin_unlock(&rng->jent_lock);
+ mutex_unlock(&rng->jent_lock);
}
static int jent_kcapi_init(struct crypto_tfm *tfm)
@@ -228,7 +229,7 @@ static int jent_kcapi_init(struct crypto_tfm *tfm)
struct shash_desc *sdesc;
int size, ret = 0;
- spin_lock_init(&rng->jent_lock);
+ mutex_init(&rng->jent_lock);
/* Use SHA3-256 as conditioner */
hash = crypto_alloc_shash(JENT_CONDITIONING_HASH, 0, 0);
@@ -257,7 +258,6 @@ static int jent_kcapi_init(struct crypto_tfm *tfm)
goto err;
}
- spin_lock_init(&rng->jent_lock);
return 0;
err:
@@ -272,7 +272,7 @@ static int jent_kcapi_random(struct crypto_rng *tfm,
struct jitterentropy *rng = crypto_rng_ctx(tfm);
int ret = 0;
- spin_lock(&rng->jent_lock);
+ mutex_lock(&rng->jent_lock);
ret = jent_read_entropy(rng->entropy_collector, rdata, dlen);
@@ -298,7 +298,7 @@ static int jent_kcapi_random(struct crypto_rng *tfm,
ret = -EINVAL;
}
- spin_unlock(&rng->jent_lock);
+ mutex_unlock(&rng->jent_lock);
return ret;
}
diff --git a/crypto/simd.c b/crypto/simd.c
index f71c4a334c7d..4e6f437e9e77 100644
--- a/crypto/simd.c
+++ b/crypto/simd.c
@@ -214,13 +214,17 @@ int simd_register_skciphers_compat(struct skcipher_alg *algs, int count,
const char *basename;
struct simd_skcipher_alg *simd;
+ for (i = 0; i < count; i++) {
+ if (WARN_ON(strncmp(algs[i].base.cra_name, "__", 2) ||
+ strncmp(algs[i].base.cra_driver_name, "__", 2)))
+ return -EINVAL;
+ }
+
err = crypto_register_skciphers(algs, count);
if (err)
return err;
for (i = 0; i < count; i++) {
- WARN_ON(strncmp(algs[i].base.cra_name, "__", 2));
- WARN_ON(strncmp(algs[i].base.cra_driver_name, "__", 2));
algname = algs[i].base.cra_name + 2;
drvname = algs[i].base.cra_driver_name + 2;
basename = algs[i].base.cra_driver_name;
@@ -437,13 +441,17 @@ int simd_register_aeads_compat(struct aead_alg *algs, int count,
const char *basename;
struct simd_aead_alg *simd;
+ for (i = 0; i < count; i++) {
+ if (WARN_ON(strncmp(algs[i].base.cra_name, "__", 2) ||
+ strncmp(algs[i].base.cra_driver_name, "__", 2)))
+ return -EINVAL;
+ }
+
err = crypto_register_aeads(algs, count);
if (err)
return err;
for (i = 0; i < count; i++) {
- WARN_ON(strncmp(algs[i].base.cra_name, "__", 2));
- WARN_ON(strncmp(algs[i].base.cra_driver_name, "__", 2));
algname = algs[i].base.cra_name + 2;
drvname = algs[i].base.cra_driver_name + 2;
basename = algs[i].base.cra_driver_name;
diff --git a/drivers/accel/amdxdna/amdxdna_mailbox.c b/drivers/accel/amdxdna/amdxdna_mailbox.c
index 46d844a73a94..e681a090752d 100644
--- a/drivers/accel/amdxdna/amdxdna_mailbox.c
+++ b/drivers/accel/amdxdna/amdxdna_mailbox.c
@@ -499,7 +499,7 @@ xdna_mailbox_start_channel(struct mailbox_channel *mb_chann,
int ret;
if (!is_power_of_2(x2i->rb_size) || !is_power_of_2(i2x->rb_size)) {
- pr_err("Ring buf size must be power of 2");
+ pr_err("Ring buf size must be power of 2\n");
return -EINVAL;
}
diff --git a/drivers/accel/rocket/rocket_gem.c b/drivers/accel/rocket/rocket_gem.c
index b6a385d2edfc..c8084719208a 100644
--- a/drivers/accel/rocket/rocket_gem.c
+++ b/drivers/accel/rocket/rocket_gem.c
@@ -145,6 +145,8 @@ int rocket_ioctl_prep_bo(struct drm_device *dev, void *data, struct drm_file *fi
ret = dma_resv_wait_timeout(gem_obj->resv, DMA_RESV_USAGE_WRITE, true, timeout);
if (!ret)
ret = timeout ? -ETIMEDOUT : -EBUSY;
+ else if (ret > 0)
+ ret = 0;
shmem_obj = &to_rocket_bo(gem_obj)->base;
diff --git a/drivers/acpi/apei/einj-core.c b/drivers/acpi/apei/einj-core.c
index a9248af078f6..1f3fa2278584 100644
--- a/drivers/acpi/apei/einj-core.c
+++ b/drivers/acpi/apei/einj-core.c
@@ -401,8 +401,18 @@ static struct acpi_generic_address *einj_get_trigger_parameter_region(
return NULL;
}
+
+static bool is_memory_injection(u32 type, u32 flags)
+{
+ if (flags & SETWA_FLAGS_EINJV2)
+ return !!(type & ACPI_EINJV2_MEMORY);
+ if (type & ACPI5_VENDOR_BIT)
+ return !!(vendor_flags & SETWA_FLAGS_MEM);
+ return !!(type & MEM_ERROR_MASK) || !!(flags & SETWA_FLAGS_MEM);
+}
+
/* Execute instructions in trigger error action table */
-static int __einj_error_trigger(u64 trigger_paddr, u32 type,
+static int __einj_error_trigger(u64 trigger_paddr, u32 type, u32 flags,
u64 param1, u64 param2)
{
struct acpi_einj_trigger trigger_tab;
@@ -480,7 +490,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type,
* This will cause resource conflict with regular memory. So
* remove it from trigger table resources.
*/
- if ((param_extension || acpi5) && (type & MEM_ERROR_MASK) && param2) {
+ if ((param_extension || acpi5) && is_memory_injection(type, flags)) {
struct apei_resources addr_resources;
apei_resources_init(&addr_resources);
@@ -660,7 +670,7 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
return rc;
trigger_paddr = apei_exec_ctx_get_output(&ctx);
if (notrigger == 0) {
- rc = __einj_error_trigger(trigger_paddr, type, param1, param2);
+ rc = __einj_error_trigger(trigger_paddr, type, flags, param1, param2);
if (rc)
return rc;
}
@@ -718,35 +728,30 @@ int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3,
SETWA_FLAGS_PCIE_SBDF | SETWA_FLAGS_EINJV2)))
return -EINVAL;
+ /*
+ * Injections targeting a CXL 1.0/1.1 port have to be injected
+ * via the einj_cxl_rch_error_inject() path as that does the proper
+ * validation of the given RCRB base (MMIO) address.
+ */
+ if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM))
+ return -EINVAL;
+
/* check if type is a valid EINJv2 error type */
if (is_v2) {
if (!(type & available_error_type_v2))
return -EINVAL;
}
- /*
- * We need extra sanity checks for memory errors.
- * Other types leap directly to injection.
- */
/* ensure param1/param2 existed */
if (!(param_extension || acpi5))
goto inject;
- /* ensure injection is memory related */
- if (type & ACPI5_VENDOR_BIT) {
- if (vendor_flags != SETWA_FLAGS_MEM)
- goto inject;
- } else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM)) {
- goto inject;
- }
-
/*
- * Injections targeting a CXL 1.0/1.1 port have to be injected
- * via the einj_cxl_rch_error_inject() path as that does the proper
- * validation of the given RCRB base (MMIO) address.
+ * We need extra sanity checks for memory errors.
+ * Other types leap directly to injection.
*/
- if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM))
- return -EINVAL;
+ if (!is_memory_injection(type, flags))
+ goto inject;
/*
* Disallow crazy address masks that give BIOS leeway to pick
diff --git a/drivers/acpi/arm64/agdi.c b/drivers/acpi/arm64/agdi.c
index feb4b2cb4618..0c2d9d6c160b 100644
--- a/drivers/acpi/arm64/agdi.c
+++ b/drivers/acpi/arm64/agdi.c
@@ -36,7 +36,7 @@ static int agdi_sdei_probe(struct platform_device *pdev,
err = sdei_event_register(adata->sdei_event, agdi_sdei_handler, pdev);
if (err) {
- dev_err(&pdev->dev, "Failed to register for SDEI event %d",
+ dev_err(&pdev->dev, "Failed to register for SDEI event %d\n",
adata->sdei_event);
return err;
}
diff --git a/drivers/acpi/x86/cmos_rtc.c b/drivers/acpi/x86/cmos_rtc.c
index 51643ff6fe5f..45db7e51cbe6 100644
--- a/drivers/acpi/x86/cmos_rtc.c
+++ b/drivers/acpi/x86/cmos_rtc.c
@@ -24,72 +24,91 @@ static const struct acpi_device_id acpi_cmos_rtc_ids[] = {
{}
};
-static acpi_status
-acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address,
- u32 bits, u64 *value64,
- void *handler_context, void *region_context)
+static bool cmos_rtc_space_handler_present __read_mostly;
+
+static acpi_status acpi_cmos_rtc_space_handler(u32 function,
+ acpi_physical_address address,
+ u32 bits, u64 *value64,
+ void *handler_context,
+ void *region_context)
{
- int i;
+ unsigned int i, bytes = DIV_ROUND_UP(bits, 8);
u8 *value = (u8 *)value64;
if (address > 0xff || !value64)
return AE_BAD_PARAMETER;
- if (function != ACPI_WRITE && function != ACPI_READ)
- return AE_BAD_PARAMETER;
+ guard(spinlock_irq)(&rtc_lock);
+
+ if (function == ACPI_WRITE) {
+ for (i = 0; i < bytes; i++, address++, value++)
+ CMOS_WRITE(*value, address);
- spin_lock_irq(&rtc_lock);
+ return AE_OK;
+ }
- for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value)
- if (function == ACPI_READ)
+ if (function == ACPI_READ) {
+ for (i = 0; i < bytes; i++, address++, value++)
*value = CMOS_READ(address);
- else
- CMOS_WRITE(*value, address);
- spin_unlock_irq(&rtc_lock);
+ return AE_OK;
+ }
- return AE_OK;
+ return AE_BAD_PARAMETER;
}
int acpi_install_cmos_rtc_space_handler(acpi_handle handle)
{
acpi_status status;
+ if (cmos_rtc_space_handler_present)
+ return 0;
+
status = acpi_install_address_space_handler(handle,
- ACPI_ADR_SPACE_CMOS,
- &acpi_cmos_rtc_space_handler,
- NULL, NULL);
+ ACPI_ADR_SPACE_CMOS,
+ acpi_cmos_rtc_space_handler,
+ NULL, NULL);
if (ACPI_FAILURE(status)) {
- pr_err("Error installing CMOS-RTC region handler\n");
+ pr_err("Failed to install CMOS-RTC address space handler\n");
return -ENODEV;
}
+ cmos_rtc_space_handler_present = true;
+
return 1;
}
EXPORT_SYMBOL_GPL(acpi_install_cmos_rtc_space_handler);
void acpi_remove_cmos_rtc_space_handler(acpi_handle handle)
{
- if (ACPI_FAILURE(acpi_remove_address_space_handler(handle,
- ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler)))
- pr_err("Error removing CMOS-RTC region handler\n");
+ acpi_status status;
+
+ if (cmos_rtc_space_handler_present)
+ return;
+
+ status = acpi_remove_address_space_handler(handle,
+ ACPI_ADR_SPACE_CMOS,
+ acpi_cmos_rtc_space_handler);
+ if (ACPI_FAILURE(status))
+ pr_err("Failed to remove CMOS-RTC address space handler\n");
}
EXPORT_SYMBOL_GPL(acpi_remove_cmos_rtc_space_handler);
-static int acpi_cmos_rtc_attach_handler(struct acpi_device *adev, const struct acpi_device_id *id)
+static int acpi_cmos_rtc_attach(struct acpi_device *adev,
+ const struct acpi_device_id *id)
{
- return acpi_install_cmos_rtc_space_handler(adev->handle);
-}
+ int ret;
-static void acpi_cmos_rtc_detach_handler(struct acpi_device *adev)
-{
- acpi_remove_cmos_rtc_space_handler(adev->handle);
+ ret = acpi_install_cmos_rtc_space_handler(adev->handle);
+ if (ret < 0)
+ return ret;
+
+ return 1;
}
static struct acpi_scan_handler cmos_rtc_handler = {
.ids = acpi_cmos_rtc_ids,
- .attach = acpi_cmos_rtc_attach_handler,
- .detach = acpi_cmos_rtc_detach_handler,
+ .attach = acpi_cmos_rtc_attach,
};
void __init acpi_cmos_rtc_init(void)
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 3b65df914ebb..cd607911d724 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1692,7 +1692,7 @@ void ata_scsi_requeue_deferred_qc(struct ata_port *ap)
/*
* If we have a deferred qc when a reset occurs or NCQ commands fail,
* do not try to be smart about what to do with this deferred command
- * and simply retry it by completing it with DID_SOFT_ERROR.
+ * and simply requeue it by completing it with DID_REQUEUE.
*/
if (!qc)
return;
@@ -1701,7 +1701,7 @@ void ata_scsi_requeue_deferred_qc(struct ata_port *ap)
ap->deferred_qc = NULL;
cancel_work(&ap->deferred_qc_work);
ata_qc_free(qc);
- scmd->result = (DID_SOFT_ERROR << 16);
+ scmd->result = (DID_REQUEUE << 16);
scsi_done(scmd);
}
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index 171750c1f691..ce519b98a189 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -940,6 +940,8 @@ void *devm_krealloc(struct device *dev, void *ptr, size_t new_size, gfp_t gfp)
if (!new_dr)
return NULL;
+ set_node_dbginfo(&new_dr->node, "devm_krealloc_release", new_size);
+
/*
* The spinlock protects the linked list against concurrent
* modifications but not the resource itself.
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index e201f0087a0f..728ecc431b38 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -3378,8 +3378,10 @@ int drbd_adm_dump_devices(struct sk_buff *skb, struct netlink_callback *cb)
if (resource_filter) {
retcode = ERR_RES_NOT_KNOWN;
resource = drbd_find_resource(nla_data(resource_filter));
- if (!resource)
+ if (!resource) {
+ rcu_read_lock();
goto put_result;
+ }
cb->args[0] = (long)resource;
}
}
@@ -3628,8 +3630,10 @@ int drbd_adm_dump_peer_devices(struct sk_buff *skb, struct netlink_callback *cb)
if (resource_filter) {
retcode = ERR_RES_NOT_KNOWN;
resource = drbd_find_resource(nla_data(resource_filter));
- if (!resource)
+ if (!resource) {
+ rcu_read_lock();
goto put_result;
+ }
}
cb->args[0] = (long)resource;
}
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 63aeb7a76a8c..0bdb804fca83 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -2910,22 +2910,26 @@ static void ublk_stop_dev(struct ublk_device *ub)
ublk_cancel_dev(ub);
}
+static void ublk_reset_io_flags(struct ublk_queue *ubq, struct ublk_io *io)
+{
+ /* UBLK_IO_FLAG_CANCELED can be cleared now */
+ spin_lock(&ubq->cancel_lock);
+ io->flags &= ~UBLK_IO_FLAG_CANCELED;
+ spin_unlock(&ubq->cancel_lock);
+}
+
/* reset per-queue io flags */
static void ublk_queue_reset_io_flags(struct ublk_queue *ubq)
{
- int j;
-
- /* UBLK_IO_FLAG_CANCELED can be cleared now */
spin_lock(&ubq->cancel_lock);
- for (j = 0; j < ubq->q_depth; j++)
- ubq->ios[j].flags &= ~UBLK_IO_FLAG_CANCELED;
ubq->canceling = false;
spin_unlock(&ubq->cancel_lock);
ubq->fail_io = false;
}
/* device can only be started after all IOs are ready */
-static void ublk_mark_io_ready(struct ublk_device *ub, u16 q_id)
+static void ublk_mark_io_ready(struct ublk_device *ub, u16 q_id,
+ struct ublk_io *io)
__must_hold(&ub->mutex)
{
struct ublk_queue *ubq = ublk_get_queue(ub, q_id);
@@ -2934,6 +2938,7 @@ static void ublk_mark_io_ready(struct ublk_device *ub, u16 q_id)
ub->unprivileged_daemons = true;
ubq->nr_io_ready++;
+ ublk_reset_io_flags(ubq, io);
/* Check if this specific queue is now fully ready */
if (ublk_queue_ready(ubq)) {
@@ -3196,7 +3201,7 @@ static int ublk_fetch(struct io_uring_cmd *cmd, struct ublk_device *ub,
if (!ret)
ret = ublk_config_io_buf(ub, io, cmd, buf_addr, NULL);
if (!ret)
- ublk_mark_io_ready(ub, q_id);
+ ublk_mark_io_ready(ub, q_id, io);
mutex_unlock(&ub->mutex);
return ret;
}
@@ -3604,7 +3609,7 @@ static int ublk_batch_prep_io(struct ublk_queue *ubq,
ublk_io_unlock(io);
if (!ret)
- ublk_mark_io_ready(data->ub, ubq->q_id);
+ ublk_mark_io_ready(data->ub, ubq->q_id, io);
return ret;
}
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 85943da0cdca..aaaef8dd8253 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1748,6 +1748,10 @@ static ssize_t algorithm_params_store(struct device *dev,
}
}
+ guard(rwsem_write)(&zram->dev_lock);
+ if (init_done(zram))
+ return -EBUSY;
+
/* Lookup priority by algorithm name */
if (algo) {
s32 p;
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index 31ff133b6159..a4b4dacfd2ad 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -678,8 +678,8 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
case BTMTK_WMT_FUNC_CTRL:
if (!skb_pull_data(data->evt_skb,
sizeof(wmt_evt_funcc->status))) {
- err = -EINVAL;
- goto err_free_skb;
+ status = BTMTK_WMT_ON_UNDONE;
+ break;
}
wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 71c1997a0f73..275ea865bc29 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -692,6 +692,9 @@ static int hci_uart_register_dev(struct hci_uart *hu)
if (hci_register_dev(hdev) < 0) {
BT_ERR("Can't register HCI device");
+ percpu_down_write(&hu->proto_lock);
+ clear_bit(HCI_UART_PROTO_INIT, &hu->flags);
+ percpu_up_write(&hu->proto_lock);
hu->proto->close(hu);
hu->hdev = NULL;
hci_free_dev(hdev);
diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index c117745cf206..221146e4860b 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -86,12 +86,16 @@ static int fsl_mc_bus_match(struct device *dev, const struct device_driver *drv)
struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
const struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(drv);
bool found = false;
+ int ret;
/* When driver_override is set, only bind to the matching driver */
- if (mc_dev->driver_override) {
- found = !strcmp(mc_dev->driver_override, mc_drv->driver.name);
+ ret = device_match_driver_override(dev, drv);
+ if (ret > 0) {
+ found = true;
goto out;
}
+ if (ret == 0)
+ goto out;
if (!mc_drv->match_id_table)
goto out;
@@ -210,39 +214,8 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(modalias);
-static ssize_t driver_override_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
- int ret;
-
- if (WARN_ON(dev->bus != &fsl_mc_bus_type))
- return -EINVAL;
-
- ret = driver_set_override(dev, &mc_dev->driver_override, buf, count);
- if (ret)
- return ret;
-
- return count;
-}
-
-static ssize_t driver_override_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
- ssize_t len;
-
- device_lock(dev);
- len = sysfs_emit(buf, "%s\n", mc_dev->driver_override);
- device_unlock(dev);
- return len;
-}
-static DEVICE_ATTR_RW(driver_override);
-
static struct attribute *fsl_mc_dev_attrs[] = {
&dev_attr_modalias.attr,
- &dev_attr_driver_override.attr,
NULL,
};
@@ -345,6 +318,7 @@ ATTRIBUTE_GROUPS(fsl_mc_bus);
const struct bus_type fsl_mc_bus_type = {
.name = "fsl-mc",
+ .driver_override = true,
.match = fsl_mc_bus_match,
.uevent = fsl_mc_bus_uevent,
.probe = fsl_mc_probe,
@@ -910,9 +884,6 @@ static struct notifier_block fsl_mc_nb;
*/
void fsl_mc_device_remove(struct fsl_mc_device *mc_dev)
{
- kfree(mc_dev->driver_override);
- mc_dev->driver_override = NULL;
-
/*
* The device-specific remove callback will get invoked by device_del()
*/
diff --git a/drivers/bus/stm32_rifsc.c b/drivers/bus/stm32_rifsc.c
index debeaf8ea1bd..5682c086ba1e 100644
--- a/drivers/bus/stm32_rifsc.c
+++ b/drivers/bus/stm32_rifsc.c
@@ -688,34 +688,6 @@ static int stm32_rifsc_grant_access(struct stm32_firewall_controller *ctrl, u32
sec_reg_value = readl(rifsc_controller->mmio + RIFSC_RISC_SECCFGR0 + 0x4 * reg_id);
cid_reg_value = readl(rifsc_controller->mmio + RIFSC_RISC_PER0_CIDCFGR + 0x8 * firewall_id);
- /* First check conditions for semaphore mode, which doesn't take into account static CID. */
- if ((cid_reg_value & CIDCFGR_SEMEN) && (cid_reg_value & CIDCFGR_CFEN)) {
- if (cid_reg_value & BIT(RIF_CID1 + SEMWL_SHIFT)) {
- /* Static CID is irrelevant if semaphore mode */
- goto skip_cid_check;
- } else {
- dev_dbg(rifsc_controller->dev,
- "Invalid bus semaphore configuration: index %d\n", firewall_id);
- return -EACCES;
- }
- }
-
- /*
- * Skip CID check if CID filtering isn't enabled or filtering is enabled on CID0, which
- * corresponds to whatever CID.
- */
- if (!(cid_reg_value & CIDCFGR_CFEN) ||
- FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) == RIF_CID0)
- goto skip_cid_check;
-
- /* Coherency check with the CID configuration */
- if (FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) != RIF_CID1) {
- dev_dbg(rifsc_controller->dev, "Invalid CID configuration for peripheral: %d\n",
- firewall_id);
- return -EACCES;
- }
-
-skip_cid_check:
/* Check security configuration */
if (sec_reg_value & BIT(reg_offset)) {
dev_dbg(rifsc_controller->dev,
@@ -723,19 +695,31 @@ static int stm32_rifsc_grant_access(struct stm32_firewall_controller *ctrl, u32
return -EACCES;
}
- /*
- * If the peripheral is in semaphore mode, take the semaphore so that
- * the CID1 has the ownership.
- */
- if ((cid_reg_value & CIDCFGR_SEMEN) && (cid_reg_value & CIDCFGR_CFEN)) {
+ /* Skip CID check if CID filtering isn't enabled */
+ if (!(cid_reg_value & CIDCFGR_CFEN))
+ goto skip_cid_check;
+
+ /* First check conditions for semaphore mode, which doesn't take into account static CID. */
+ if (cid_reg_value & CIDCFGR_SEMEN) {
+ if (!(cid_reg_value & BIT(RIF_CID1 + SEMWL_SHIFT))) {
+ dev_dbg(rifsc_controller->dev,
+ "Invalid bus semaphore configuration: index %d\n", firewall_id);
+ return -EACCES;
+ }
+
rc = stm32_rif_acquire_semaphore(rifsc_controller, firewall_id);
if (rc) {
- dev_err(rifsc_controller->dev,
+ dev_dbg(rifsc_controller->dev,
"Couldn't acquire semaphore for peripheral: %d\n", firewall_id);
return rc;
}
+ } else if (FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) != RIF_CID1) {
+ dev_dbg(rifsc_controller->dev, "Invalid CID configuration for peripheral: %d\n",
+ firewall_id);
+ return -EACCES;
}
+skip_cid_check:
return 0;
}
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index fc049612d6dc..62934cf4b10d 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -631,6 +631,16 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi)
WARN_ON(!cdo->generic_packet);
+ /*
+ * Propagate the drive's write support to the block layer so BLKROGET
+ * reflects actual write capability. Drivers that use GET CONFIGURATION
+ * features (CDC_MRW_W, CDC_RAM) must have called
+ * cdrom_probe_write_features() before register_cdrom() so the mask is
+ * complete here.
+ */
+ set_disk_ro(disk, !CDROM_CAN(CDC_DVD_RAM | CDC_MRW_W | CDC_RAM |
+ CDC_CD_RW));
+
cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
mutex_lock(&cdrom_mutex);
list_add(&cdi->list, &cdrom_list);
@@ -742,6 +752,44 @@ static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write)
return 0;
}
+/*
+ * Probe write-related MMC features via GET CONFIGURATION and update
+ * cdi->mask accordingly. Drivers that populate cdi->mask from the MODE SENSE
+ * capabilities page (e.g. sr) should call this after those MODE SENSE bits
+ * have been set but before register_cdrom(), so that the full set of
+ * write-capability bits is known by the time register_cdrom() decides on the
+ * initial read-only state of the disk.
+ */
+void cdrom_probe_write_features(struct cdrom_device_info *cdi)
+{
+ int mrw, mrw_write, ram_write;
+
+ mrw = 0;
+ if (!cdrom_is_mrw(cdi, &mrw_write))
+ mrw = 1;
+
+ if (CDROM_CAN(CDC_MO_DRIVE))
+ ram_write = 1;
+ else
+ (void) cdrom_is_random_writable(cdi, &ram_write);
+
+ if (mrw)
+ cdi->mask &= ~CDC_MRW;
+ else
+ cdi->mask |= CDC_MRW;
+
+ if (mrw_write)
+ cdi->mask &= ~CDC_MRW_W;
+ else
+ cdi->mask |= CDC_MRW_W;
+
+ if (ram_write)
+ cdi->mask &= ~CDC_RAM;
+ else
+ cdi->mask |= CDC_RAM;
+}
+EXPORT_SYMBOL(cdrom_probe_write_features);
+
static int cdrom_media_erasable(struct cdrom_device_info *cdi)
{
disc_information di;
@@ -894,33 +942,8 @@ static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi)
*/
static int cdrom_open_write(struct cdrom_device_info *cdi)
{
- int mrw, mrw_write, ram_write;
int ret = 1;
- mrw = 0;
- if (!cdrom_is_mrw(cdi, &mrw_write))
- mrw = 1;
-
- if (CDROM_CAN(CDC_MO_DRIVE))
- ram_write = 1;
- else
- (void) cdrom_is_random_writable(cdi, &ram_write);
-
- if (mrw)
- cdi->mask &= ~CDC_MRW;
- else
- cdi->mask |= CDC_MRW;
-
- if (mrw_write)
- cdi->mask &= ~CDC_MRW_W;
- else
- cdi->mask |= CDC_MRW_W;
-
- if (ram_write)
- cdi->mask &= ~CDC_RAM;
- else
- cdi->mask |= CDC_RAM;
-
if (CDROM_CAN(CDC_MRW_W))
ret = cdrom_mrw_open_write(cdi);
else if (CDROM_CAN(CDC_DVD_RAM))
diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c
index 7a52e3ea49ed..a45e80d13e10 100644
--- a/drivers/char/ipmi/ssif_bmc.c
+++ b/drivers/char/ipmi/ssif_bmc.c
@@ -163,6 +163,8 @@ static ssize_t ssif_bmc_read(struct file *file, char __user *buf, size_t count,
spin_unlock_irqrestore(&ssif_bmc->lock, flags);
ret = copy_to_user(buf, &msg, count);
+ if (ret > 0)
+ ret = -EFAULT;
}
return (ret < 0) ? ret : count;
@@ -456,6 +458,15 @@ static bool supported_write_cmd(u8 cmd)
return false;
}
+static bool supported_write_start_cmd(u8 cmd)
+{
+ if (cmd == SSIF_IPMI_SINGLEPART_WRITE ||
+ cmd == SSIF_IPMI_MULTIPART_WRITE_START)
+ return true;
+
+ return false;
+}
+
/* Process the IPMI response that will be read by master */
static void handle_read_processed(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
{
@@ -558,7 +569,7 @@ static void process_request_part(struct ssif_bmc_ctx *ssif_bmc)
len = ssif_bmc->request.len + part->length;
/* Do the bound check here, not allow the request len exceed 254 bytes */
if (len > IPMI_SSIF_PAYLOAD_MAX) {
- dev_warn(&ssif_bmc->client->dev,
+ dev_dbg(&ssif_bmc->client->dev,
"Warn: Request exceeded 254 bytes, aborting");
/* Request too long, aborting */
ssif_bmc->aborting = true;
@@ -604,7 +615,7 @@ static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
ssif_bmc->state == SSIF_START ||
ssif_bmc->state == SSIF_REQ_RECVING ||
ssif_bmc->state == SSIF_RES_SENDING) {
- dev_warn(&ssif_bmc->client->dev,
+ dev_dbg(&ssif_bmc->client->dev,
"Warn: %s unexpected READ REQUESTED in state=%s\n",
__func__, state_to_string(ssif_bmc->state));
ssif_bmc->state = SSIF_ABORTING;
@@ -613,7 +624,7 @@ static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
} else if (ssif_bmc->state == SSIF_SMBUS_CMD) {
if (!supported_read_cmd(ssif_bmc->part_buf.smbus_cmd)) {
- dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus read command=0x%x",
+ dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown SMBus read command=0x%x",
ssif_bmc->part_buf.smbus_cmd);
ssif_bmc->aborting = true;
}
@@ -648,7 +659,7 @@ static void on_read_processed_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
ssif_bmc->state == SSIF_START ||
ssif_bmc->state == SSIF_REQ_RECVING ||
ssif_bmc->state == SSIF_SMBUS_CMD) {
- dev_warn(&ssif_bmc->client->dev,
+ dev_dbg(&ssif_bmc->client->dev,
"Warn: %s unexpected READ PROCESSED in state=%s\n",
__func__, state_to_string(ssif_bmc->state));
ssif_bmc->state = SSIF_ABORTING;
@@ -673,7 +684,7 @@ static void on_write_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
} else if (ssif_bmc->state == SSIF_START ||
ssif_bmc->state == SSIF_REQ_RECVING ||
ssif_bmc->state == SSIF_RES_SENDING) {
- dev_warn(&ssif_bmc->client->dev,
+ dev_dbg(&ssif_bmc->client->dev,
"Warn: %s unexpected WRITE REQUEST in state=%s\n",
__func__, state_to_string(ssif_bmc->state));
ssif_bmc->state = SSIF_ABORTING;
@@ -688,7 +699,7 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
{
if (ssif_bmc->state == SSIF_READY ||
ssif_bmc->state == SSIF_RES_SENDING) {
- dev_warn(&ssif_bmc->client->dev,
+ dev_dbg(&ssif_bmc->client->dev,
"Warn: %s unexpected WRITE RECEIVED in state=%s\n",
__func__, state_to_string(ssif_bmc->state));
ssif_bmc->state = SSIF_ABORTING;
@@ -698,7 +709,7 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
} else if (ssif_bmc->state == SSIF_SMBUS_CMD) {
if (!supported_write_cmd(ssif_bmc->part_buf.smbus_cmd)) {
- dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus write command=0x%x",
+ dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown SMBus write command=0x%x",
ssif_bmc->part_buf.smbus_cmd);
ssif_bmc->aborting = true;
}
@@ -707,6 +718,11 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
ssif_bmc->state = SSIF_ABORTING;
else
ssif_bmc->state = SSIF_REQ_RECVING;
+ } else if (ssif_bmc->state == SSIF_ABORTING) {
+ if (supported_write_start_cmd(*val)) {
+ ssif_bmc->state = SSIF_SMBUS_CMD;
+ ssif_bmc->aborting = false;
+ }
}
/* This is response sending state */
@@ -722,7 +738,7 @@ static void on_stop_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
ssif_bmc->state == SSIF_START ||
ssif_bmc->state == SSIF_SMBUS_CMD ||
ssif_bmc->state == SSIF_ABORTING) {
- dev_warn(&ssif_bmc->client->dev,
+ dev_dbg(&ssif_bmc->client->dev,
"Warn: %s unexpected SLAVE STOP in state=%s\n",
__func__, state_to_string(ssif_bmc->state));
ssif_bmc->state = SSIF_READY;
@@ -789,7 +805,7 @@ static int ssif_bmc_cb(struct i2c_client *client, enum i2c_slave_event event, u8
break;
default:
- dev_warn(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n");
+ dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n");
break;
}
diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c
index f05631e55310..2524c5c0eb46 100644
--- a/drivers/clk/clk-qoriq.c
+++ b/drivers/clk/clk-qoriq.c
@@ -907,13 +907,11 @@ static const struct clockgen_pll_div *get_pll_div(struct clockgen *cg,
return &cg->pll[pll].div[div];
}
-static struct clk * __init create_mux_common(struct clockgen *cg,
- struct mux_hwclock *hwc,
- const struct clk_ops *ops,
- unsigned long min_rate,
- unsigned long max_rate,
- unsigned long pct80_rate,
- const char *fmt, int idx)
+static struct clk * __init __printf(7, 8)
+create_mux_common(struct clockgen *cg, struct mux_hwclock *hwc,
+ const struct clk_ops *ops, unsigned long min_rate,
+ unsigned long max_rate, unsigned long pct80_rate,
+ const char *fmt, ...)
{
struct clk_init_data init = {};
struct clk *clk;
@@ -921,8 +919,11 @@ static struct clk * __init create_mux_common(struct clockgen *cg,
const char *parent_names[NUM_MUX_PARENTS];
char name[32];
int i, j;
+ va_list args;
- snprintf(name, sizeof(name), fmt, idx);
+ va_start(args, fmt);
+ vsnprintf(name, sizeof(name), fmt, args);
+ va_end(args);
for (i = 0, j = 0; i < NUM_MUX_PARENTS; i++) {
unsigned long rate;
diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c
index ba3b1057e4f0..abb6c8fcdc91 100644
--- a/drivers/clk/clk-xgene.c
+++ b/drivers/clk/clk-xgene.c
@@ -188,6 +188,8 @@ static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_ty
of_clk_add_provider(np, of_clk_src_simple_get, clk);
clk_register_clkdev(clk, clk_name, NULL);
pr_debug("Add %s clock PLL\n", clk_name);
+ } else {
+ iounmap(reg);
}
}
diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index f726c00aba72..35e6b59c01db 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -188,9 +188,11 @@ static void of_assigned_ldb_sels(struct device_node *node,
}
if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) {
pr_err("ccm: parent clock %d not in ccm\n", index);
+ of_node_put(clkspec.np);
return;
}
parent = clkspec.args[0];
+ of_node_put(clkspec.np);
rc = of_parse_phandle_with_args(node, "assigned-clocks",
"#clock-cells", index, &clkspec);
@@ -198,9 +200,11 @@ static void of_assigned_ldb_sels(struct device_node *node,
return;
if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) {
pr_err("ccm: child clock %d not in ccm\n", index);
+ of_node_put(clkspec.np);
return;
}
child = clkspec.args[0];
+ of_node_put(clkspec.np);
if (child != IMX6QDL_CLK_LDB_DI0_SEL &&
child != IMX6QDL_CLK_LDB_DI1_SEL)
@@ -238,8 +242,11 @@ static bool pll6_bypassed(struct device_node *node)
return false;
if (clkspec.np == node &&
- clkspec.args[0] == IMX6QDL_PLL6_BYPASS)
+ clkspec.args[0] == IMX6QDL_PLL6_BYPASS) {
+ of_node_put(clkspec.np);
break;
+ }
+ of_node_put(clkspec.np);
}
/* PLL6 bypass is not part of the assigned clock list */
@@ -249,6 +256,9 @@ static bool pll6_bypassed(struct device_node *node)
ret = of_parse_phandle_with_args(node, "assigned-clock-parents",
"#clock-cells", index, &clkspec);
+ if (!ret)
+ of_node_put(clkspec.np);
+
if (clkspec.args[0] != IMX6QDL_CLK_PLL6)
return true;
diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c
index f70ed231b92d..cedc8a02aa1f 100644
--- a/drivers/clk/imx/clk-imx8mq.c
+++ b/drivers/clk/imx/clk-imx8mq.c
@@ -237,7 +237,7 @@ static const char * const imx8mq_dsi_esc_sels[] = {"osc_25m", "sys2_pll_100m", "
static const char * const imx8mq_csi1_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m",
"sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", };
-static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m",
+static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m",
"sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", };
static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m",
@@ -246,7 +246,7 @@ static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m",
static const char * const imx8mq_csi2_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m",
"sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", };
-static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m",
+static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m",
"sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", };
static const char * const imx8mq_csi2_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m",
diff --git a/drivers/clk/qcom/dispcc-glymur.c b/drivers/clk/qcom/dispcc-glymur.c
index 5203fa6383f6..bef74f58405b 100644
--- a/drivers/clk/qcom/dispcc-glymur.c
+++ b/drivers/clk/qcom/dispcc-glymur.c
@@ -417,7 +417,7 @@ static struct clk_rcg2 disp_cc_mdss_dptx1_aux_clk_src = {
.parent_data = disp_cc_parent_data_1,
.num_parents = ARRAY_SIZE(disp_cc_parent_data_1),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_dp_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -747,7 +747,6 @@ static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = {
&disp_cc_mdss_byte0_clk_src.clkr.hw,
},
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_regmap_div_ops,
},
};
@@ -762,7 +761,6 @@ static struct clk_regmap_div disp_cc_mdss_byte1_div_clk_src = {
&disp_cc_mdss_byte1_clk_src.clkr.hw,
},
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_regmap_div_ops,
},
};
diff --git a/drivers/clk/qcom/dispcc-kaanapali.c b/drivers/clk/qcom/dispcc-kaanapali.c
index baae2ec1f72a..c1578cd07041 100644
--- a/drivers/clk/qcom/dispcc-kaanapali.c
+++ b/drivers/clk/qcom/dispcc-kaanapali.c
@@ -800,7 +800,6 @@ static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = {
&disp_cc_mdss_byte0_clk_src.clkr.hw,
},
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_regmap_div_ops,
},
};
@@ -815,7 +814,6 @@ static struct clk_regmap_div disp_cc_mdss_byte1_div_clk_src = {
&disp_cc_mdss_byte1_clk_src.clkr.hw,
},
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_regmap_div_ops,
},
};
diff --git a/drivers/clk/qcom/dispcc-milos.c b/drivers/clk/qcom/dispcc-milos.c
index 95b6dd89d9ae..339cb1c63ba7 100644
--- a/drivers/clk/qcom/dispcc-milos.c
+++ b/drivers/clk/qcom/dispcc-milos.c
@@ -394,7 +394,6 @@ static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = {
&disp_cc_mdss_byte0_clk_src.clkr.hw,
},
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_regmap_div_ops,
},
};
diff --git a/drivers/clk/qcom/dispcc-sc8280xp.c b/drivers/clk/qcom/dispcc-sc8280xp.c
index 5903a759d4af..e91dfed0f37e 100644
--- a/drivers/clk/qcom/dispcc-sc8280xp.c
+++ b/drivers/clk/qcom/dispcc-sc8280xp.c
@@ -1160,7 +1160,6 @@ static struct clk_regmap_div disp0_cc_mdss_byte0_div_clk_src = {
&disp0_cc_mdss_byte0_clk_src.clkr.hw,
},
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_regmap_div_ops,
},
};
@@ -1175,7 +1174,6 @@ static struct clk_regmap_div disp1_cc_mdss_byte0_div_clk_src = {
&disp1_cc_mdss_byte0_clk_src.clkr.hw,
},
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_regmap_div_ops,
},
};
@@ -1190,7 +1188,6 @@ static struct clk_regmap_div disp0_cc_mdss_byte1_div_clk_src = {
&disp0_cc_mdss_byte1_clk_src.clkr.hw,
},
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_regmap_div_ops,
},
};
@@ -1205,7 +1202,6 @@ static struct clk_regmap_div disp1_cc_mdss_byte1_div_clk_src = {
&disp1_cc_mdss_byte1_clk_src.clkr.hw,
},
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_regmap_div_ops,
},
};
diff --git a/drivers/clk/qcom/dispcc-sm4450.c b/drivers/clk/qcom/dispcc-sm4450.c
index e8752d01c8e6..2fdacc26df69 100644
--- a/drivers/clk/qcom/dispcc-sm4450.c
+++ b/drivers/clk/qcom/dispcc-sm4450.c
@@ -335,7 +335,6 @@ static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = {
&disp_cc_mdss_byte0_clk_src.clkr.hw,
},
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_regmap_div_ops,
},
};
diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c
index 8f433e1e7028..e59cdadd5647 100644
--- a/drivers/clk/qcom/dispcc-sm8250.c
+++ b/drivers/clk/qcom/dispcc-sm8250.c
@@ -578,7 +578,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = {
.name = "disp_cc_mdss_pclk0_clk_src",
.parent_data = disp_cc_parent_data_6,
.num_parents = ARRAY_SIZE(disp_cc_parent_data_6),
- .flags = CLK_SET_RATE_PARENT,
+ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
.ops = &clk_pixel_ops,
},
};
@@ -592,7 +592,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = {
.name = "disp_cc_mdss_pclk1_clk_src",
.parent_data = disp_cc_parent_data_6,
.num_parents = ARRAY_SIZE(disp_cc_parent_data_6),
- .flags = CLK_SET_RATE_PARENT,
+ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
.ops = &clk_pixel_ops,
},
};
@@ -632,7 +632,7 @@ static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = {
.parent_data = disp_cc_parent_data_1,
.num_parents = ARRAY_SIZE(disp_cc_parent_data_1),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
diff --git a/drivers/clk/qcom/dispcc-sm8450.c b/drivers/clk/qcom/dispcc-sm8450.c
index 9ce9fd28e55b..2e91332dd92a 100644
--- a/drivers/clk/qcom/dispcc-sm8450.c
+++ b/drivers/clk/qcom/dispcc-sm8450.c
@@ -409,7 +409,7 @@ static struct clk_rcg2 disp_cc_mdss_dptx1_aux_clk_src = {
.parent_data = disp_cc_parent_data_1,
.num_parents = ARRAY_SIZE(disp_cc_parent_data_1),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_dp_ops,
+ .ops = &clk_rcg2_ops,
},
};
diff --git a/drivers/clk/qcom/dispcc0-sa8775p.c b/drivers/clk/qcom/dispcc0-sa8775p.c
index aeda9cf4bfee..b248fa970587 100644
--- a/drivers/clk/qcom/dispcc0-sa8775p.c
+++ b/drivers/clk/qcom/dispcc0-sa8775p.c
@@ -591,7 +591,6 @@ static struct clk_regmap_div mdss_0_disp_cc_mdss_byte0_div_clk_src = {
&mdss_0_disp_cc_mdss_byte0_clk_src.clkr.hw,
},
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_regmap_div_ops,
},
};
@@ -606,7 +605,6 @@ static struct clk_regmap_div mdss_0_disp_cc_mdss_byte1_div_clk_src = {
&mdss_0_disp_cc_mdss_byte1_clk_src.clkr.hw,
},
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_regmap_div_ops,
},
};
diff --git a/drivers/clk/qcom/dispcc1-sa8775p.c b/drivers/clk/qcom/dispcc1-sa8775p.c
index cd55d1c11902..9882edbb79f9 100644
--- a/drivers/clk/qcom/dispcc1-sa8775p.c
+++ b/drivers/clk/qcom/dispcc1-sa8775p.c
@@ -591,7 +591,6 @@ static struct clk_regmap_div mdss_1_disp_cc_mdss_byte0_div_clk_src = {
&mdss_1_disp_cc_mdss_byte0_clk_src.clkr.hw,
},
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_regmap_div_ops,
},
};
@@ -606,7 +605,6 @@ static struct clk_regmap_div mdss_1_disp_cc_mdss_byte1_div_clk_src = {
&mdss_1_disp_cc_mdss_byte1_clk_src.clkr.hw,
},
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_regmap_div_ops,
},
};
diff --git a/drivers/clk/qcom/gcc-glymur.c b/drivers/clk/qcom/gcc-glymur.c
index 238e205735ed..cd11470a75f3 100644
--- a/drivers/clk/qcom/gcc-glymur.c
+++ b/drivers/clk/qcom/gcc-glymur.c
@@ -8507,6 +8507,7 @@ static const struct qcom_reset_map gcc_glymur_resets[] = {
[GCC_VIDEO_AXI0_CLK_ARES] = { 0x3201c, 2 },
[GCC_VIDEO_AXI1_CLK_ARES] = { 0x32044, 2 },
[GCC_VIDEO_BCR] = { 0x32000 },
+ [GCC_VIDEO_AXI0C_CLK_ARES] = { 0x32030, 2 },
};
static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = {
diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c
index 31e788e22ab4..4095a1f54a09 100644
--- a/drivers/clk/qcom/gcc-sc8180x.c
+++ b/drivers/clk/qcom/gcc-sc8180x.c
@@ -4172,7 +4172,7 @@ static struct gdsc usb30_sec_gdsc = {
.pd = {
.name = "usb30_sec_gdsc",
},
- .pwrsts = PWRSTS_OFF_ON,
+ .pwrsts = PWRSTS_RET_ON,
.flags = POLL_CFG_GDSCR,
};
@@ -4190,7 +4190,7 @@ static struct gdsc usb30_prim_gdsc = {
.pd = {
.name = "usb30_prim_gdsc",
},
- .pwrsts = PWRSTS_OFF_ON,
+ .pwrsts = PWRSTS_RET_ON,
.flags = POLL_CFG_GDSCR,
};
@@ -4199,7 +4199,7 @@ static struct gdsc pcie_0_gdsc = {
.pd = {
.name = "pcie_0_gdsc",
},
- .pwrsts = PWRSTS_OFF_ON,
+ .pwrsts = PWRSTS_RET_ON,
.flags = POLL_CFG_GDSCR,
};
@@ -4226,7 +4226,7 @@ static struct gdsc pcie_1_gdsc = {
.pd = {
.name = "pcie_1_gdsc",
},
- .pwrsts = PWRSTS_OFF_ON,
+ .pwrsts = PWRSTS_RET_ON,
.flags = POLL_CFG_GDSCR,
};
@@ -4235,7 +4235,7 @@ static struct gdsc pcie_2_gdsc = {
.pd = {
.name = "pcie_2_gdsc",
},
- .pwrsts = PWRSTS_OFF_ON,
+ .pwrsts = PWRSTS_RET_ON,
.flags = POLL_CFG_GDSCR,
};
@@ -4253,7 +4253,7 @@ static struct gdsc pcie_3_gdsc = {
.pd = {
.name = "pcie_3_gdsc",
},
- .pwrsts = PWRSTS_OFF_ON,
+ .pwrsts = PWRSTS_RET_ON,
.flags = POLL_CFG_GDSCR,
};
@@ -4262,10 +4262,55 @@ static struct gdsc usb30_mp_gdsc = {
.pd = {
.name = "usb30_mp_gdsc",
},
- .pwrsts = PWRSTS_OFF_ON,
+ .pwrsts = PWRSTS_RET_ON,
.flags = POLL_CFG_GDSCR,
};
+static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc = {
+ .gdscr = 0x7d050,
+ .pd = {
+ .name = "hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = VOTABLE,
+};
+
+static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc = {
+ .gdscr = 0x7d058,
+ .pd = {
+ .name = "hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = VOTABLE,
+};
+
+static struct gdsc hlos1_vote_mmnoc_mmu_tbu_sf_gdsc = {
+ .gdscr = 0x7d054,
+ .pd = {
+ .name = "hlos1_vote_mmnoc_mmu_tbu_sf_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = VOTABLE,
+};
+
+static struct gdsc hlos1_vote_turing_mmu_tbu0_gdsc = {
+ .gdscr = 0x7d05c,
+ .pd = {
+ .name = "hlos1_vote_turing_mmu_tbu0_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = VOTABLE,
+};
+
+static struct gdsc hlos1_vote_turing_mmu_tbu1_gdsc = {
+ .gdscr = 0x7d060,
+ .pd = {
+ .name = "hlos1_vote_turing_mmu_tbu1_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = VOTABLE,
+};
+
static struct clk_regmap *gcc_sc8180x_clocks[] = {
[GCC_AGGRE_NOC_PCIE_TBU_CLK] = &gcc_aggre_noc_pcie_tbu_clk.clkr,
[GCC_AGGRE_UFS_CARD_AXI_CLK] = &gcc_aggre_ufs_card_axi_clk.clkr,
@@ -4595,6 +4640,11 @@ static struct gdsc *gcc_sc8180x_gdscs[] = {
[USB30_MP_GDSC] = &usb30_mp_gdsc,
[USB30_PRIM_GDSC] = &usb30_prim_gdsc,
[USB30_SEC_GDSC] = &usb30_sec_gdsc,
+ [HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc,
+ [HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc,
+ [HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_sf_gdsc,
+ [HLOS1_VOTE_TURING_MMU_TBU0_GDSC] = &hlos1_vote_turing_mmu_tbu0_gdsc,
+ [HLOS1_VOTE_TURING_MMU_TBU1_GDSC] = &hlos1_vote_turing_mmu_tbu1_gdsc,
};
static const struct regmap_config gcc_sc8180x_regmap_config = {
diff --git a/drivers/clk/qcom/gcc-x1e80100.c b/drivers/clk/qcom/gcc-x1e80100.c
index 74afd12c158c..73a2a5112623 100644
--- a/drivers/clk/qcom/gcc-x1e80100.c
+++ b/drivers/clk/qcom/gcc-x1e80100.c
@@ -7480,6 +7480,7 @@ static int gcc_x1e80100_probe(struct platform_device *pdev)
qcom_branch_set_clk_en(regmap, 0x32004); /* GCC_VIDEO_AHB_CLK */
qcom_branch_set_clk_en(regmap, 0x32030); /* GCC_VIDEO_XO_CLK */
qcom_branch_set_clk_en(regmap, 0x71004); /* GCC_GPU_CFG_AHB_CLK */
+ qcom_branch_set_clk_en(regmap, 0x7d01c); /* GCC_HLOS1_VOTE_AGGRE_NOC_MMU_USB_QTB_CLK */
/* Clear GDSC_SLEEP_ENA_VOTE to stop votes being auto-removed in sleep. */
regmap_write(regmap, 0x52224, 0x0);
diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c
index 7deabf8400cf..95aa07120245 100644
--- a/drivers/clk/qcom/gdsc.c
+++ b/drivers/clk/qcom/gdsc.c
@@ -518,10 +518,20 @@ static int gdsc_add_subdomain_list(struct dev_pm_domain_list *pd_list,
ret = pm_genpd_add_subdomain(genpd, subdomain);
if (ret)
- return ret;
+ goto remove_added_subdomains;
}
return 0;
+
+remove_added_subdomains:
+ for (i--; i >= 0; i--) {
+ struct device *dev = pd_list->pd_devs[i];
+ struct generic_pm_domain *genpd = pd_to_genpd(dev->pm_domain);
+
+ pm_genpd_remove_subdomain(genpd, subdomain);
+ }
+
+ return ret;
}
static void gdsc_remove_subdomain_list(struct dev_pm_domain_list *pd_list,
diff --git a/drivers/clk/renesas/r9a09g056-cpg.c b/drivers/clk/renesas/r9a09g056-cpg.c
index fead173cae8b..70de6bb929b9 100644
--- a/drivers/clk/renesas/r9a09g056-cpg.c
+++ b/drivers/clk/renesas/r9a09g056-cpg.c
@@ -289,6 +289,24 @@ static const struct rzv2h_mod_clk r9a09g056_mod_clks[] __initconst = {
BUS_MSTOP(5, BIT(13))),
DEF_MOD("wdt_3_clk_loco", CLK_QEXTAL, 5, 2, 2, 18,
BUS_MSTOP(5, BIT(13))),
+ DEF_MOD("rspi_0_pclk", CLK_PLLCLN_DIV8, 5, 4, 2, 20,
+ BUS_MSTOP(11, BIT(0))),
+ DEF_MOD("rspi_0_pclk_sfr", CLK_PLLCLN_DIV8, 5, 5, 2, 21,
+ BUS_MSTOP(11, BIT(0))),
+ DEF_MOD("rspi_0_tclk", CLK_PLLCLN_DIV8, 5, 6, 2, 22,
+ BUS_MSTOP(11, BIT(0))),
+ DEF_MOD("rspi_1_pclk", CLK_PLLCLN_DIV8, 5, 7, 2, 23,
+ BUS_MSTOP(11, BIT(1))),
+ DEF_MOD("rspi_1_pclk_sfr", CLK_PLLCLN_DIV8, 5, 8, 2, 24,
+ BUS_MSTOP(11, BIT(1))),
+ DEF_MOD("rspi_1_tclk", CLK_PLLCLN_DIV8, 5, 9, 2, 25,
+ BUS_MSTOP(11, BIT(1))),
+ DEF_MOD("rspi_2_pclk", CLK_PLLCLN_DIV8, 5, 10, 2, 26,
+ BUS_MSTOP(11, BIT(2))),
+ DEF_MOD("rspi_2_pclk_sfr", CLK_PLLCLN_DIV8, 5, 11, 2, 27,
+ BUS_MSTOP(11, BIT(2))),
+ DEF_MOD("rspi_2_tclk", CLK_PLLCLN_DIV8, 5, 12, 2, 28,
+ BUS_MSTOP(11, BIT(2))),
DEF_MOD("rsci0_pclk", CLK_PLLCLN_DIV16, 5, 13, 2, 29,
BUS_MSTOP(11, BIT(3))),
DEF_MOD("rsci0_tclk", CLK_PLLCLN_DIV16, 5, 14, 2, 30,
@@ -389,24 +407,6 @@ static const struct rzv2h_mod_clk r9a09g056_mod_clks[] __initconst = {
BUS_MSTOP(11, BIT(12))),
DEF_MOD("rsci9_ps_ps1_n", CLK_PLLCLN_DIV64, 8, 14, 4, 14,
BUS_MSTOP(11, BIT(12))),
- DEF_MOD("rspi_0_pclk", CLK_PLLCLN_DIV8, 5, 4, 2, 20,
- BUS_MSTOP(11, BIT(0))),
- DEF_MOD("rspi_0_pclk_sfr", CLK_PLLCLN_DIV8, 5, 5, 2, 21,
- BUS_MSTOP(11, BIT(0))),
- DEF_MOD("rspi_0_tclk", CLK_PLLCLN_DIV8, 5, 6, 2, 22,
- BUS_MSTOP(11, BIT(0))),
- DEF_MOD("rspi_1_pclk", CLK_PLLCLN_DIV8, 5, 7, 2, 23,
- BUS_MSTOP(11, BIT(1))),
- DEF_MOD("rspi_1_pclk_sfr", CLK_PLLCLN_DIV8, 5, 8, 2, 24,
- BUS_MSTOP(11, BIT(1))),
- DEF_MOD("rspi_1_tclk", CLK_PLLCLN_DIV8, 5, 9, 2, 25,
- BUS_MSTOP(11, BIT(1))),
- DEF_MOD("rspi_2_pclk", CLK_PLLCLN_DIV8, 5, 10, 2, 26,
- BUS_MSTOP(11, BIT(2))),
- DEF_MOD("rspi_2_pclk_sfr", CLK_PLLCLN_DIV8, 5, 11, 2, 27,
- BUS_MSTOP(11, BIT(2))),
- DEF_MOD("rspi_2_tclk", CLK_PLLCLN_DIV8, 5, 12, 2, 28,
- BUS_MSTOP(11, BIT(2))),
DEF_MOD("scif_0_clk_pck", CLK_PLLCM33_DIV16, 8, 15, 4, 15,
BUS_MSTOP(3, BIT(14))),
DEF_MOD("i3c_0_pclkrw", CLK_PLLCLN_DIV16, 9, 0, 4, 16,
diff --git a/drivers/clk/renesas/r9a09g057-cpg.c b/drivers/clk/renesas/r9a09g057-cpg.c
index 6943cad318b5..c3174f40fdb4 100644
--- a/drivers/clk/renesas/r9a09g057-cpg.c
+++ b/drivers/clk/renesas/r9a09g057-cpg.c
@@ -280,22 +280,30 @@ static const struct rzv2h_mod_clk r9a09g057_mod_clks[] __initconst = {
BUS_MSTOP(11, BIT(15))),
DEF_MOD("gtm_7_pclk", CLK_PLLCLN_DIV16, 4, 10, 2, 10,
BUS_MSTOP(12, BIT(0))),
- DEF_MOD("wdt_0_clkp", CLK_PLLCM33_DIV16, 4, 11, 2, 11,
- BUS_MSTOP(3, BIT(10))),
- DEF_MOD("wdt_0_clk_loco", CLK_QEXTAL, 4, 12, 2, 12,
- BUS_MSTOP(3, BIT(10))),
DEF_MOD("wdt_1_clkp", CLK_PLLCLN_DIV16, 4, 13, 2, 13,
BUS_MSTOP(1, BIT(0))),
DEF_MOD("wdt_1_clk_loco", CLK_QEXTAL, 4, 14, 2, 14,
BUS_MSTOP(1, BIT(0))),
- DEF_MOD("wdt_2_clkp", CLK_PLLCLN_DIV16, 4, 15, 2, 15,
- BUS_MSTOP(5, BIT(12))),
- DEF_MOD("wdt_2_clk_loco", CLK_QEXTAL, 5, 0, 2, 16,
- BUS_MSTOP(5, BIT(12))),
- DEF_MOD("wdt_3_clkp", CLK_PLLCLN_DIV16, 5, 1, 2, 17,
- BUS_MSTOP(5, BIT(13))),
- DEF_MOD("wdt_3_clk_loco", CLK_QEXTAL, 5, 2, 2, 18,
- BUS_MSTOP(5, BIT(13))),
+ DEF_MOD("rtc_0_clk_rtc", CLK_PLLCM33_DIV16, 5, 3, 2, 19,
+ BUS_MSTOP(3, BIT(11) | BIT(12))),
+ DEF_MOD("rspi_0_pclk", CLK_PLLCLN_DIV8, 5, 4, 2, 20,
+ BUS_MSTOP(11, BIT(0))),
+ DEF_MOD("rspi_0_pclk_sfr", CLK_PLLCLN_DIV8, 5, 5, 2, 21,
+ BUS_MSTOP(11, BIT(0))),
+ DEF_MOD("rspi_0_tclk", CLK_PLLCLN_DIV8, 5, 6, 2, 22,
+ BUS_MSTOP(11, BIT(0))),
+ DEF_MOD("rspi_1_pclk", CLK_PLLCLN_DIV8, 5, 7, 2, 23,
+ BUS_MSTOP(11, BIT(1))),
+ DEF_MOD("rspi_1_pclk_sfr", CLK_PLLCLN_DIV8, 5, 8, 2, 24,
+ BUS_MSTOP(11, BIT(1))),
+ DEF_MOD("rspi_1_tclk", CLK_PLLCLN_DIV8, 5, 9, 2, 25,
+ BUS_MSTOP(11, BIT(1))),
+ DEF_MOD("rspi_2_pclk", CLK_PLLCLN_DIV8, 5, 10, 2, 26,
+ BUS_MSTOP(11, BIT(2))),
+ DEF_MOD("rspi_2_pclk_sfr", CLK_PLLCLN_DIV8, 5, 11, 2, 27,
+ BUS_MSTOP(11, BIT(2))),
+ DEF_MOD("rspi_2_tclk", CLK_PLLCLN_DIV8, 5, 12, 2, 28,
+ BUS_MSTOP(11, BIT(2))),
DEF_MOD("rsci0_pclk", CLK_PLLCLN_DIV16, 5, 13, 2, 29,
BUS_MSTOP(11, BIT(3))),
DEF_MOD("rsci0_tclk", CLK_PLLCLN_DIV16, 5, 14, 2, 30,
@@ -396,26 +404,6 @@ static const struct rzv2h_mod_clk r9a09g057_mod_clks[] __initconst = {
BUS_MSTOP(11, BIT(12))),
DEF_MOD("rsci9_ps_ps1_n", CLK_PLLCLN_DIV64, 8, 14, 4, 14,
BUS_MSTOP(11, BIT(12))),
- DEF_MOD("rtc_0_clk_rtc", CLK_PLLCM33_DIV16, 5, 3, 2, 19,
- BUS_MSTOP(3, BIT(11) | BIT(12))),
- DEF_MOD("rspi_0_pclk", CLK_PLLCLN_DIV8, 5, 4, 2, 20,
- BUS_MSTOP(11, BIT(0))),
- DEF_MOD("rspi_0_pclk_sfr", CLK_PLLCLN_DIV8, 5, 5, 2, 21,
- BUS_MSTOP(11, BIT(0))),
- DEF_MOD("rspi_0_tclk", CLK_PLLCLN_DIV8, 5, 6, 2, 22,
- BUS_MSTOP(11, BIT(0))),
- DEF_MOD("rspi_1_pclk", CLK_PLLCLN_DIV8, 5, 7, 2, 23,
- BUS_MSTOP(11, BIT(1))),
- DEF_MOD("rspi_1_pclk_sfr", CLK_PLLCLN_DIV8, 5, 8, 2, 24,
- BUS_MSTOP(11, BIT(1))),
- DEF_MOD("rspi_1_tclk", CLK_PLLCLN_DIV8, 5, 9, 2, 25,
- BUS_MSTOP(11, BIT(1))),
- DEF_MOD("rspi_2_pclk", CLK_PLLCLN_DIV8, 5, 10, 2, 26,
- BUS_MSTOP(11, BIT(2))),
- DEF_MOD("rspi_2_pclk_sfr", CLK_PLLCLN_DIV8, 5, 11, 2, 27,
- BUS_MSTOP(11, BIT(2))),
- DEF_MOD("rspi_2_tclk", CLK_PLLCLN_DIV8, 5, 12, 2, 28,
- BUS_MSTOP(11, BIT(2))),
DEF_MOD("scif_0_clk_pck", CLK_PLLCM33_DIV16, 8, 15, 4, 15,
BUS_MSTOP(3, BIT(14))),
DEF_MOD("i3c_0_pclkrw", CLK_PLLCLN_DIV16, 9, 0, 4, 16,
@@ -598,10 +586,7 @@ static const struct rzv2h_reset r9a09g057_resets[] __initconst = {
DEF_RST(7, 2, 3, 3), /* GTM_5_PRESETZ */
DEF_RST(7, 3, 3, 4), /* GTM_6_PRESETZ */
DEF_RST(7, 4, 3, 5), /* GTM_7_PRESETZ */
- DEF_RST(7, 5, 3, 6), /* WDT_0_RESET */
DEF_RST(7, 6, 3, 7), /* WDT_1_RESET */
- DEF_RST(7, 7, 3, 8), /* WDT_2_RESET */
- DEF_RST(7, 8, 3, 9), /* WDT_3_RESET */
DEF_RST(8, 1, 3, 18), /* RSCI0_PRESETN */
DEF_RST(8, 2, 3, 19), /* RSCI0_TRESETN */
DEF_RST(8, 3, 3, 20), /* RSCI1_PRESETN */
diff --git a/drivers/clk/spacemit/ccu_mix.c b/drivers/clk/spacemit/ccu_mix.c
index 9578366e9746..a8b407049bf4 100644
--- a/drivers/clk/spacemit/ccu_mix.c
+++ b/drivers/clk/spacemit/ccu_mix.c
@@ -73,7 +73,7 @@ static int ccu_mix_trigger_fc(struct clk_hw *hw)
struct ccu_common *common = hw_to_ccu_common(hw);
unsigned int val;
- if (common->reg_fc)
+ if (!common->reg_fc)
return 0;
ccu_update(common, fc, common->mask_fc, common->mask_fc);
diff --git a/drivers/clk/sunxi-ng/ccu-sun55i-a523-r.c b/drivers/clk/sunxi-ng/ccu-sun55i-a523-r.c
index 0339c4af0fe5..db0e36d8838e 100644
--- a/drivers/clk/sunxi-ng/ccu-sun55i-a523-r.c
+++ b/drivers/clk/sunxi-ng/ccu-sun55i-a523-r.c
@@ -83,9 +83,22 @@ static SUNXI_CCU_MUX_DATA_WITH_GATE(r_pwmctrl_clk, "r-pwmctrl",
static SUNXI_CCU_GATE_HW(bus_r_pwmctrl_clk, "bus-r-pwmctrl",
&r_apb0_clk.common.hw, 0x13c, BIT(0), 0);
-/* SPI clock is /M/N (same as new MMC?) */
+static const struct clk_parent_data r_spi_parents[] = {
+ { .fw_name = "hosc" },
+ { .fw_name = "pll-periph" },
+ { .name = "pll-periph0-300M" },
+ { .name = "pll-periph1-300M" },
+ { .name = "pll-audio" },
+};
+static SUNXI_CCU_DUALDIV_MUX_GATE(r_spi_clk, "r-spi", r_spi_parents, 0x150,
+ 0, 5, /* M */
+ 8, 5, /* P */
+ 24, 3, /* mux */
+ BIT(31), /* gate */
+ 0);
static SUNXI_CCU_GATE_HW(bus_r_spi_clk, "bus-r-spi",
&r_ahb_clk.common.hw, 0x15c, BIT(0), 0);
+
static SUNXI_CCU_GATE_HW(bus_r_spinlock_clk, "bus-r-spinlock",
&r_ahb_clk.common.hw, 0x16c, BIT(0), 0);
static SUNXI_CCU_GATE_HW(bus_r_msgbox_clk, "bus-r-msgbox",
@@ -138,6 +151,7 @@ static struct ccu_common *sun55i_a523_r_ccu_clks[] = {
&bus_r_twd_clk.common,
&r_pwmctrl_clk.common,
&bus_r_pwmctrl_clk.common,
+ &r_spi_clk.common,
&bus_r_spi_clk.common,
&bus_r_spinlock_clk.common,
&bus_r_msgbox_clk.common,
@@ -169,6 +183,7 @@ static struct clk_hw_onecell_data sun55i_a523_r_hw_clks = {
[CLK_BUS_R_TWD] = &bus_r_twd_clk.common.hw,
[CLK_R_PWMCTRL] = &r_pwmctrl_clk.common.hw,
[CLK_BUS_R_PWMCTRL] = &bus_r_pwmctrl_clk.common.hw,
+ [CLK_R_SPI] = &r_spi_clk.common.hw,
[CLK_BUS_R_SPI] = &bus_r_spi_clk.common.hw,
[CLK_BUS_R_SPINLOCK] = &bus_r_spinlock_clk.common.hw,
[CLK_BUS_R_MSGBOX] = &bus_r_msgbox_clk.common.hw,
diff --git a/drivers/clk/visconti/pll.c b/drivers/clk/visconti/pll.c
index 6fd02c4b641e..805b95481281 100644
--- a/drivers/clk/visconti/pll.c
+++ b/drivers/clk/visconti/pll.c
@@ -249,7 +249,7 @@ static struct clk_hw *visconti_register_pll(struct visconti_pll_provider *ctx,
const struct visconti_pll_rate_table *rate_table,
spinlock_t *lock)
{
- struct clk_init_data init;
+ struct clk_init_data init = {};
struct visconti_pll *pll;
struct clk_hw *pll_hw_clk;
size_t len;
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index 5aa9fcd80cf5..78b70bdcb008 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -261,7 +261,6 @@ static int msr_update_perf(struct cpufreq_policy *policy, u8 min_perf,
if (fast_switch) {
wrmsrq(MSR_AMD_CPPC_REQ, value);
- return 0;
} else {
int ret = wrmsrq_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, value);
@@ -713,13 +712,12 @@ static unsigned int amd_pstate_fast_switch(struct cpufreq_policy *policy,
return policy->cur;
}
-static void amd_pstate_adjust_perf(unsigned int cpu,
+static void amd_pstate_adjust_perf(struct cpufreq_policy *policy,
unsigned long _min_perf,
unsigned long target_perf,
unsigned long capacity)
{
u8 max_perf, min_perf, des_perf, cap_perf;
- struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu);
struct amd_cpudata *cpudata;
union perf_cached perf;
@@ -1533,7 +1531,7 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
ret = amd_pstate_set_epp(policy, cpudata->epp_default);
if (ret)
- return ret;
+ goto free_cpudata1;
current_pstate_driver->adjust_perf = NULL;
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 1f794524a1d9..44441ceedb76 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -2228,7 +2228,7 @@ EXPORT_SYMBOL_GPL(cpufreq_driver_fast_switch);
/**
* cpufreq_driver_adjust_perf - Adjust CPU performance level in one go.
- * @cpu: Target CPU.
+ * @policy: cpufreq policy object of the target CPU.
* @min_perf: Minimum (required) performance level (units of @capacity).
* @target_perf: Target (desired) performance level (units of @capacity).
* @capacity: Capacity of the target CPU.
@@ -2247,12 +2247,12 @@ EXPORT_SYMBOL_GPL(cpufreq_driver_fast_switch);
* parallel with either ->target() or ->target_index() or ->fast_switch() for
* the same CPU.
*/
-void cpufreq_driver_adjust_perf(unsigned int cpu,
+void cpufreq_driver_adjust_perf(struct cpufreq_policy *policy,
unsigned long min_perf,
unsigned long target_perf,
unsigned long capacity)
{
- cpufreq_driver->adjust_perf(cpu, min_perf, target_perf, capacity);
+ cpufreq_driver->adjust_perf(policy, min_perf, target_perf, capacity);
}
/**
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 11c58af41900..0f50034e4b68 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -3239,12 +3239,12 @@ static unsigned int intel_cpufreq_fast_switch(struct cpufreq_policy *policy,
return target_pstate * cpu->pstate.scaling;
}
-static void intel_cpufreq_adjust_perf(unsigned int cpunum,
+static void intel_cpufreq_adjust_perf(struct cpufreq_policy *policy,
unsigned long min_perf,
unsigned long target_perf,
unsigned long capacity)
{
- struct cpudata *cpu = all_cpu_data[cpunum];
+ struct cpudata *cpu = all_cpu_data[policy->cpu];
u64 hwp_cap = READ_ONCE(cpu->hwp_cap_cached);
int old_pstate = cpu->pstate.current_pstate;
int cap_pstate, min_pstate, max_pstate, target_pstate;
diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
index 9b0cb97055dc..b393689400b4 100644
--- a/drivers/crypto/atmel-aes.c
+++ b/drivers/crypto/atmel-aes.c
@@ -2270,10 +2270,12 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd)
/* i = ARRAY_SIZE(aes_authenc_algs); */
err_aes_authenc_alg:
crypto_unregister_aeads(aes_authenc_algs, i);
- crypto_unregister_skcipher(&aes_xts_alg);
+ if (dd->caps.has_xts)
+ crypto_unregister_skcipher(&aes_xts_alg);
#endif
err_aes_xts_alg:
- crypto_unregister_aead(&aes_gcm_alg);
+ if (dd->caps.has_gcm)
+ crypto_unregister_aead(&aes_gcm_alg);
err_aes_gcm_alg:
i = ARRAY_SIZE(aes_algs);
err_aes_algs:
diff --git a/drivers/crypto/ccp/ccp-crypto-aes.c b/drivers/crypto/ccp/ccp-crypto-aes.c
index 01d298350b92..3ad6bb7666f6 100644
--- a/drivers/crypto/ccp/ccp-crypto-aes.c
+++ b/drivers/crypto/ccp/ccp-crypto-aes.c
@@ -30,8 +30,11 @@ static int ccp_aes_complete(struct crypto_async_request *async_req, int ret)
if (ret)
return ret;
- if (ctx->u.aes.mode != CCP_AES_MODE_ECB)
- memcpy(req->iv, rctx->iv, AES_BLOCK_SIZE);
+ if (ctx->u.aes.mode != CCP_AES_MODE_ECB) {
+ size_t ivsize = crypto_skcipher_ivsize(crypto_skcipher_reqtfm(req));
+
+ memcpy(req->iv, rctx->iv, ivsize);
+ }
return 0;
}
diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c
index 15174216d8c4..2471a4dd0b50 100644
--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c
+++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c
@@ -230,7 +230,7 @@ static int qp_send_message(struct sec_req *req)
spin_unlock_bh(&qp_ctx->req_lock);
- atomic64_inc(&req->ctx->sec->debug.dfx.send_cnt);
+ atomic64_inc(&qp_ctx->ctx->sec->debug.dfx.send_cnt);
return -EINPROGRESS;
}
diff --git a/drivers/crypto/inside-secure/eip93/eip93-common.c b/drivers/crypto/inside-secure/eip93/eip93-common.c
index f4ad6beff15e..259714a4ee4d 100644
--- a/drivers/crypto/inside-secure/eip93/eip93-common.c
+++ b/drivers/crypto/inside-secure/eip93/eip93-common.c
@@ -731,7 +731,7 @@ int eip93_hmac_setkey(u32 ctx_flags, const u8 *key, unsigned int keylen,
return -EINVAL;
}
- ahash_tfm = crypto_alloc_ahash(alg_name, 0, CRYPTO_ALG_ASYNC);
+ ahash_tfm = crypto_alloc_ahash(alg_name, 0, 0);
if (IS_ERR(ahash_tfm))
return PTR_ERR(ahash_tfm);
diff --git a/drivers/crypto/inside-secure/eip93/eip93-main.c b/drivers/crypto/inside-secure/eip93/eip93-main.c
index b7fd9795062d..76858bb4fcc2 100644
--- a/drivers/crypto/inside-secure/eip93/eip93-main.c
+++ b/drivers/crypto/inside-secure/eip93/eip93-main.c
@@ -36,6 +36,14 @@ static struct eip93_alg_template *eip93_algs[] = {
&eip93_alg_cbc_aes,
&eip93_alg_ctr_aes,
&eip93_alg_rfc3686_aes,
+ &eip93_alg_md5,
+ &eip93_alg_sha1,
+ &eip93_alg_sha224,
+ &eip93_alg_sha256,
+ &eip93_alg_hmac_md5,
+ &eip93_alg_hmac_sha1,
+ &eip93_alg_hmac_sha224,
+ &eip93_alg_hmac_sha256,
&eip93_alg_authenc_hmac_md5_cbc_des,
&eip93_alg_authenc_hmac_sha1_cbc_des,
&eip93_alg_authenc_hmac_sha224_cbc_des,
@@ -52,14 +60,6 @@ static struct eip93_alg_template *eip93_algs[] = {
&eip93_alg_authenc_hmac_sha1_rfc3686_aes,
&eip93_alg_authenc_hmac_sha224_rfc3686_aes,
&eip93_alg_authenc_hmac_sha256_rfc3686_aes,
- &eip93_alg_md5,
- &eip93_alg_sha1,
- &eip93_alg_sha224,
- &eip93_alg_sha256,
- &eip93_alg_hmac_md5,
- &eip93_alg_hmac_sha1,
- &eip93_alg_hmac_sha224,
- &eip93_alg_hmac_sha256,
};
inline void eip93_irq_disable(struct eip93_device *eip93, u32 mask)
diff --git a/drivers/crypto/inside-secure/eip93/eip93-regs.h b/drivers/crypto/inside-secure/eip93/eip93-regs.h
index 0490b8d15131..116b3fbb6ad7 100644
--- a/drivers/crypto/inside-secure/eip93/eip93-regs.h
+++ b/drivers/crypto/inside-secure/eip93/eip93-regs.h
@@ -109,7 +109,7 @@
#define EIP93_REG_PE_BUF_THRESH 0x10c
#define EIP93_PE_OUTBUF_THRESH GENMASK(23, 16)
#define EIP93_PE_INBUF_THRESH GENMASK(7, 0)
-#define EIP93_REG_PE_INBUF_COUNT 0x100
+#define EIP93_REG_PE_INBUF_COUNT 0x110
#define EIP93_REG_PE_OUTBUF_COUNT 0x114
#define EIP93_REG_PE_BUF_RW_PNTR 0x118 /* BUF_PNTR */
diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c
index 547abf453d4a..f62b994e18e5 100644
--- a/drivers/crypto/intel/iaa/iaa_crypto_main.c
+++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c
@@ -906,8 +906,8 @@ static void rebalance_wq_table(void)
return;
}
+ cpu = 0;
for_each_node_with_cpus(node) {
- cpu = 0;
node_cpus = cpumask_of_node(node);
for_each_cpu(node_cpu, node_cpus) {
diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c
index 35105213d40c..0002122219bc 100644
--- a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c
+++ b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c
@@ -97,9 +97,25 @@ static struct adf_hw_device_class adf_420xx_class = {
static u32 get_ae_mask(struct adf_hw_device_data *self)
{
- u32 me_disable = self->fuses[ADF_FUSECTL4];
+ unsigned long fuses = self->fuses[ADF_FUSECTL4];
+ u32 mask = ADF_420XX_ACCELENGINES_MASK;
- return ~me_disable & ADF_420XX_ACCELENGINES_MASK;
+ if (test_bit(0, &fuses))
+ mask &= ~ADF_AE_GROUP_0;
+
+ if (test_bit(4, &fuses))
+ mask &= ~ADF_AE_GROUP_1;
+
+ if (test_bit(8, &fuses))
+ mask &= ~ADF_AE_GROUP_2;
+
+ if (test_bit(12, &fuses))
+ mask &= ~ADF_AE_GROUP_3;
+
+ if (test_bit(16, &fuses))
+ mask &= ~ADF_AE_GROUP_4;
+
+ return mask;
}
static u32 uof_get_num_objs(struct adf_accel_dev *accel_dev)
diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c
index 740f68a36ac5..900f19b90b2d 100644
--- a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c
+++ b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c
@@ -100,9 +100,19 @@ static struct adf_hw_device_class adf_4xxx_class = {
static u32 get_ae_mask(struct adf_hw_device_data *self)
{
- u32 me_disable = self->fuses[ADF_FUSECTL4];
+ unsigned long fuses = self->fuses[ADF_FUSECTL4];
+ u32 mask = ADF_4XXX_ACCELENGINES_MASK;
- return ~me_disable & ADF_4XXX_ACCELENGINES_MASK;
+ if (test_bit(0, &fuses))
+ mask &= ~ADF_AE_GROUP_0;
+
+ if (test_bit(4, &fuses))
+ mask &= ~ADF_AE_GROUP_1;
+
+ if (test_bit(8, &fuses))
+ mask &= ~ADF_AE_GROUP_2;
+
+ return mask;
}
static u32 get_accel_cap(struct adf_accel_dev *accel_dev)
diff --git a/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c b/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c
index e97c67c87b3c..6abb57bfd328 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c
@@ -13,14 +13,14 @@ static ssize_t errors_correctable_show(struct device *dev,
char *buf)
{
struct adf_accel_dev *accel_dev;
- unsigned long counter;
+ int counter;
accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
if (!accel_dev)
return -EINVAL;
counter = ADF_RAS_ERR_CTR_READ(accel_dev->ras_errors, ADF_RAS_CORR);
- return scnprintf(buf, PAGE_SIZE, "%ld\n", counter);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", counter);
}
static ssize_t errors_nonfatal_show(struct device *dev,
@@ -28,14 +28,14 @@ static ssize_t errors_nonfatal_show(struct device *dev,
char *buf)
{
struct adf_accel_dev *accel_dev;
- unsigned long counter;
+ int counter;
accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
if (!accel_dev)
return -EINVAL;
counter = ADF_RAS_ERR_CTR_READ(accel_dev->ras_errors, ADF_RAS_UNCORR);
- return scnprintf(buf, PAGE_SIZE, "%ld\n", counter);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", counter);
}
static ssize_t errors_fatal_show(struct device *dev,
@@ -43,14 +43,14 @@ static ssize_t errors_fatal_show(struct device *dev,
char *buf)
{
struct adf_accel_dev *accel_dev;
- unsigned long counter;
+ int counter;
accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
if (!accel_dev)
return -EINVAL;
counter = ADF_RAS_ERR_CTR_READ(accel_dev->ras_errors, ADF_RAS_FATAL);
- return scnprintf(buf, PAGE_SIZE, "%ld\n", counter);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", counter);
}
static ssize_t reset_error_counters_store(struct device *dev,
diff --git a/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h b/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h
index 7ea8962272f2..d28732225c9e 100644
--- a/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h
+++ b/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h
@@ -3,6 +3,8 @@
#ifndef _ICP_QAT_HW_20_COMP_H_
#define _ICP_QAT_HW_20_COMP_H_
+#include <linux/swab.h>
+
#include "icp_qat_hw_20_comp_defs.h"
#include "icp_qat_fw.h"
@@ -54,7 +56,7 @@ ICP_QAT_FW_COMP_20_BUILD_CONFIG_LOWER(struct icp_qat_hw_comp_20_config_csr_lower
QAT_FIELD_SET(val32, csr.abd, ICP_QAT_HW_COMP_20_CONFIG_CSR_ABD_BITPOS,
ICP_QAT_HW_COMP_20_CONFIG_CSR_ABD_MASK);
- return __builtin_bswap32(val32);
+ return swab32(val32);
}
struct icp_qat_hw_comp_20_config_csr_upper {
@@ -106,7 +108,7 @@ ICP_QAT_FW_COMP_20_BUILD_CONFIG_UPPER(struct icp_qat_hw_comp_20_config_csr_upper
ICP_QAT_HW_COMP_20_CONFIG_CSR_NICE_PARAM_BITPOS,
ICP_QAT_HW_COMP_20_CONFIG_CSR_NICE_PARAM_MASK);
- return __builtin_bswap32(val32);
+ return swab32(val32);
}
struct icp_qat_hw_decomp_20_config_csr_lower {
@@ -138,7 +140,7 @@ ICP_QAT_FW_DECOMP_20_BUILD_CONFIG_LOWER(struct icp_qat_hw_decomp_20_config_csr_l
ICP_QAT_HW_DECOMP_20_CONFIG_CSR_LZ4_BLOCK_CHECKSUM_PRESENT_BITPOS,
ICP_QAT_HW_DECOMP_20_CONFIG_CSR_LZ4_BLOCK_CHECKSUM_PRESENT_MASK);
- return __builtin_bswap32(val32);
+ return swab32(val32);
}
struct icp_qat_hw_decomp_20_config_csr_upper {
@@ -158,7 +160,7 @@ ICP_QAT_FW_DECOMP_20_BUILD_CONFIG_UPPER(struct icp_qat_hw_decomp_20_config_csr_u
ICP_QAT_HW_DECOMP_20_CONFIG_CSR_MINI_CAM_CONTROL_BITPOS,
ICP_QAT_HW_DECOMP_20_CONFIG_CSR_MINI_CAM_CONTROL_MASK);
- return __builtin_bswap32(val32);
+ return swab32(val32);
}
#endif
diff --git a/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c b/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c
index 8b123472b71c..4273a0ecb6c8 100644
--- a/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c
+++ b/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c
@@ -133,7 +133,7 @@ static int qat_comp_alg_init_tfm(struct crypto_acomp *acomp_tfm)
struct crypto_tfm *tfm = crypto_acomp_tfm(acomp_tfm);
struct qat_compression_ctx *ctx = crypto_tfm_ctx(tfm);
struct qat_compression_instance *inst;
- int node;
+ int node, ret;
if (tfm->node == NUMA_NO_NODE)
node = numa_node_id();
@@ -146,7 +146,13 @@ static int qat_comp_alg_init_tfm(struct crypto_acomp *acomp_tfm)
return -EINVAL;
ctx->inst = inst;
- return qat_comp_build_ctx(inst->accel_dev, ctx->comp_ctx, QAT_DEFLATE);
+ ret = qat_comp_build_ctx(inst->accel_dev, ctx->comp_ctx, QAT_DEFLATE);
+ if (ret) {
+ qat_compression_put_instance(inst);
+ memset(ctx, 0, sizeof(*ctx));
+ }
+
+ return ret;
}
static void qat_comp_alg_exit_tfm(struct crypto_acomp *acomp_tfm)
diff --git a/drivers/crypto/sa2ul.c b/drivers/crypto/sa2ul.c
index df3defa1ef4b..965a03d5b27a 100644
--- a/drivers/crypto/sa2ul.c
+++ b/drivers/crypto/sa2ul.c
@@ -1744,13 +1744,13 @@ static int sa_cra_init_aead(struct crypto_aead *tfm, const char *hash,
static int sa_cra_init_aead_sha1(struct crypto_aead *tfm)
{
return sa_cra_init_aead(tfm, "sha1",
- "authenc(hmac(sha1-ce),cbc(aes-ce))");
+ "authenc(hmac(sha1),cbc(aes))");
}
static int sa_cra_init_aead_sha256(struct crypto_aead *tfm)
{
return sa_cra_init_aead(tfm, "sha256",
- "authenc(hmac(sha256-ce),cbc(aes-ce))");
+ "authenc(hmac(sha256),cbc(aes))");
}
static void sa_exit_tfm_aead(struct crypto_aead *tfm)
diff --git a/drivers/crypto/tegra/tegra-se-aes.c b/drivers/crypto/tegra/tegra-se-aes.c
index 9210cceb4b7b..30c78afe3dea 100644
--- a/drivers/crypto/tegra/tegra-se-aes.c
+++ b/drivers/crypto/tegra/tegra-se-aes.c
@@ -4,6 +4,7 @@
* Crypto driver to handle block cipher algorithms using NVIDIA Security Engine.
*/
+#include <linux/bottom_half.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
@@ -333,7 +334,9 @@ static int tegra_aes_do_one_req(struct crypto_engine *engine, void *areq)
tegra_key_invalidate_reserved(ctx->se, key2_id, ctx->alg);
out_finalize:
+ local_bh_disable();
crypto_finalize_skcipher_request(se->engine, req, ret);
+ local_bh_enable();
return 0;
}
@@ -1262,7 +1265,9 @@ static int tegra_ccm_do_one_req(struct crypto_engine *engine, void *areq)
tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg);
out_finalize:
+ local_bh_disable();
crypto_finalize_aead_request(ctx->se->engine, req, ret);
+ local_bh_enable();
return 0;
}
@@ -1348,7 +1353,9 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq)
tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg);
out_finalize:
+ local_bh_disable();
crypto_finalize_aead_request(ctx->se->engine, req, ret);
+ local_bh_enable();
return 0;
}
@@ -1746,7 +1753,9 @@ static int tegra_cmac_do_one_req(struct crypto_engine *engine, void *areq)
if (tegra_key_is_reserved(rctx->key_id))
tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg);
+ local_bh_disable();
crypto_finalize_hash_request(se->engine, req, ret);
+ local_bh_enable();
return 0;
}
diff --git a/drivers/crypto/tegra/tegra-se-hash.c b/drivers/crypto/tegra/tegra-se-hash.c
index 06bb5bf0fa33..23d549801612 100644
--- a/drivers/crypto/tegra/tegra-se-hash.c
+++ b/drivers/crypto/tegra/tegra-se-hash.c
@@ -4,6 +4,7 @@
* Crypto driver to handle HASH algorithms using NVIDIA Security Engine.
*/
+#include <linux/bottom_half.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
@@ -546,7 +547,9 @@ static int tegra_sha_do_one_req(struct crypto_engine *engine, void *areq)
}
out:
+ local_bh_disable();
crypto_finalize_hash_request(se->engine, req, ret);
+ local_bh_enable();
return 0;
}
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index fbb300a01830..a5922116db2a 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -1043,6 +1043,9 @@ static void cxl_reset_done(struct pci_dev *pdev)
* that no longer exists.
*/
guard(device)(&cxlmd->dev);
+ if (!cxlmd->dev.driver)
+ return;
+
if (cxlmd->endpoint &&
cxl_endpoint_decoder_reset_detected(cxlmd->endpoint)) {
dev_crit(dev, "SBR happened without memory regions removal.\n");
diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index 35afcfcac591..abb6d8f8f95d 100644
--- a/drivers/dma-buf/dma-fence.c
+++ b/drivers/dma-buf/dma-fence.c
@@ -1133,9 +1133,9 @@ const char __rcu *dma_fence_driver_name(struct dma_fence *fence)
"RCU protection is required for safe access to returned string");
if (!dma_fence_test_signaled_flag(fence))
- return fence->ops->get_driver_name(fence);
+ return (const char __rcu *)fence->ops->get_driver_name(fence);
else
- return "detached-driver";
+ return (const char __rcu *)"detached-driver";
}
EXPORT_SYMBOL(dma_fence_driver_name);
@@ -1165,8 +1165,8 @@ const char __rcu *dma_fence_timeline_name(struct dma_fence *fence)
"RCU protection is required for safe access to returned string");
if (!dma_fence_test_signaled_flag(fence))
- return fence->ops->get_timeline_name(fence);
+ return (const char __rcu *)fence->ops->get_driver_name(fence);
else
- return "signaled-timeline";
+ return (const char __rcu *)"signaled-timeline";
}
EXPORT_SYMBOL(dma_fence_timeline_name);
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
index 5d74bc29cf89..95e460422b2a 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -342,8 +342,8 @@ static void axi_desc_put(struct axi_dma_desc *desc)
kfree(desc);
atomic_sub(descs_put, &chan->descs_allocated);
dev_vdbg(chan2dev(chan), "%s: %d descs put, %d still allocated\n",
- axi_chan_name(chan), descs_put,
- atomic_read(&chan->descs_allocated));
+ axi_chan_name(chan), descs_put,
+ atomic_read(&chan->descs_allocated));
}
static void vchan_desc_put(struct virt_dma_desc *vdesc)
@@ -353,7 +353,7 @@ static void vchan_desc_put(struct virt_dma_desc *vdesc)
static enum dma_status
dma_chan_tx_status(struct dma_chan *dchan, dma_cookie_t cookie,
- struct dma_tx_state *txstate)
+ struct dma_tx_state *txstate)
{
struct axi_dma_chan *chan = dchan_to_axi_dma_chan(dchan);
struct virt_dma_desc *vdesc;
@@ -491,7 +491,7 @@ static void axi_chan_start_first_queued(struct axi_dma_chan *chan)
desc = vd_to_axi_desc(vd);
dev_vdbg(chan2dev(chan), "%s: started %u\n", axi_chan_name(chan),
- vd->tx.cookie);
+ vd->tx.cookie);
axi_chan_block_xfer_start(chan, desc);
}
@@ -592,8 +592,6 @@ static void dw_axi_dma_set_hw_channel(struct axi_dma_chan *chan, bool set)
(chan->id * DMA_APB_HS_SEL_BIT_SIZE));
reg_value |= (val << (chan->id * DMA_APB_HS_SEL_BIT_SIZE));
lo_hi_writeq(reg_value, chip->apb_regs + DMAC_APB_HW_HS_SEL_0);
-
- return;
}
/*
@@ -1162,7 +1160,7 @@ static irqreturn_t dw_axi_dma_interrupt(int irq, void *dev_id)
axi_chan_irq_clear(chan, status);
dev_vdbg(chip->dev, "%s %u IRQ status: 0x%08x\n",
- axi_chan_name(chan), i, status);
+ axi_chan_name(chan), i, status);
if (status & DWAXIDMAC_IRQ_ALL_ERR)
axi_chan_handle_err(chan, status);
@@ -1451,7 +1449,7 @@ static int axi_req_irqs(struct platform_device *pdev, struct axi_dma_chip *chip)
if (chip->irq[i] < 0)
return chip->irq[i];
ret = devm_request_irq(chip->dev, chip->irq[i], dw_axi_dma_interrupt,
- IRQF_SHARED, KBUILD_MODNAME, chip);
+ IRQF_SHARED, KBUILD_MODNAME, chip);
if (ret < 0)
return ret;
}
@@ -1645,7 +1643,7 @@ static void dw_remove(struct platform_device *pdev)
of_dma_controller_free(chip->dev->of_node);
list_for_each_entry_safe(chan, _chan, &dw->dma.channels,
- vc.chan.device_node) {
+ vc.chan.device_node) {
list_del(&chan->vc.chan.device_node);
tasklet_kill(&chan->vc.task);
}
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index cfb9962417ef..53f572b6b6fc 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -824,6 +824,7 @@ static int mxs_dma_probe(struct platform_device *pdev)
if (ret) {
dev_err(mxs_dma->dma_device.dev,
"failed to register controller\n");
+ return ret;
}
dev_info(mxs_dma->dma_device.dev, "initialized\n");
diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c
index 83cbd64abf5a..95ae786e98aa 100644
--- a/drivers/dpll/dpll_netlink.c
+++ b/drivers/dpll/dpll_netlink.c
@@ -842,11 +842,21 @@ int dpll_pin_delete_ntf(struct dpll_pin *pin)
return dpll_pin_event_send(DPLL_CMD_PIN_DELETE_NTF, pin);
}
+/**
+ * __dpll_pin_change_ntf - notify that the pin has been changed
+ * @pin: registered pin pointer
+ *
+ * Context: caller must hold dpll_lock. Suitable for use inside pin
+ * callbacks which are already invoked under dpll_lock.
+ * Return: 0 if succeeds, error code otherwise.
+ */
int __dpll_pin_change_ntf(struct dpll_pin *pin)
{
+ lockdep_assert_held(&dpll_lock);
dpll_pin_notify(pin, DPLL_PIN_CHANGED);
return dpll_pin_event_send(DPLL_CMD_PIN_CHANGE_NTF, pin);
}
+EXPORT_SYMBOL_GPL(__dpll_pin_change_ntf);
/**
* dpll_pin_change_ntf - notify that the pin has been changed
diff --git a/drivers/dpll/dpll_netlink.h b/drivers/dpll/dpll_netlink.h
index dd28b56d27c5..a9cfd55f57fc 100644
--- a/drivers/dpll/dpll_netlink.h
+++ b/drivers/dpll/dpll_netlink.h
@@ -11,5 +11,3 @@ int dpll_device_delete_ntf(struct dpll_device *dpll);
int dpll_pin_create_ntf(struct dpll_pin *pin);
int dpll_pin_delete_ntf(struct dpll_pin *pin);
-
-int __dpll_pin_change_ntf(struct dpll_pin *pin);
diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
index f2f94d4d533e..eb2782848283 100644
--- a/drivers/firmware/arm_ffa/driver.c
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -2078,7 +2078,7 @@ static int __init ffa_init(void)
ret = ffa_rxtx_map(virt_to_phys(drv_info->tx_buffer),
virt_to_phys(drv_info->rx_buffer),
- rxtx_bufsz / FFA_PAGE_SIZE);
+ PAGE_ALIGN(rxtx_bufsz) / FFA_PAGE_SIZE);
if (ret) {
pr_err("failed to register FFA RxTx buffers\n");
goto free_pages;
diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c
index 2c628a127091..8e8f81f0a5a0 100644
--- a/drivers/firmware/efi/capsule-loader.c
+++ b/drivers/firmware/efi/capsule-loader.c
@@ -67,7 +67,7 @@ int __efi_capsule_setup_info(struct capsule_info *cap_info)
cap_info->pages = temp_page;
temp_page = krealloc(cap_info->phys,
- pages_needed * sizeof(phys_addr_t *),
+ pages_needed * sizeof(phys_addr_t),
GFP_KERNEL | __GFP_ZERO);
if (!temp_page)
return -ENOMEM;
diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
index 8fbc96693a55..d439a9f5b62b 100644
--- a/drivers/firmware/qcom/qcom_scm.c
+++ b/drivers/firmware/qcom/qcom_scm.c
@@ -923,14 +923,13 @@ struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *c
goto free_input_rt;
}
- tbl_ptr = kzalloc(size, GFP_KERNEL);
+ tbl_ptr = kmemdup(output_rt_tzm, size, GFP_KERNEL);
if (!tbl_ptr) {
qcom_tzmem_free(output_rt_tzm);
ret = -ENOMEM;
goto free_input_rt;
}
- memcpy(tbl_ptr, output_rt_tzm, size);
*output_rt_size = size;
qcom_tzmem_free(output_rt_tzm);
diff --git a/drivers/fwctl/main.c b/drivers/fwctl/main.c
index bc6378506296..098c3824ad75 100644
--- a/drivers/fwctl/main.c
+++ b/drivers/fwctl/main.c
@@ -415,7 +415,7 @@ static void __exit fwctl_exit(void)
unregister_chrdev_region(fwctl_dev, FWCTL_MAX_DEVICES);
}
-module_init(fwctl_init);
+subsys_initcall(fwctl_init);
module_exit(fwctl_exit);
MODULE_DESCRIPTION("fwctl device firmware access framework");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
index d1bf2e150c1a..780a0078c91a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
@@ -1239,6 +1239,8 @@ static enum drm_mode_status amdgpu_connector_dvi_mode_valid(struct drm_connector
case CONNECTOR_OBJECT_ID_HDMI_TYPE_B:
max_digital_pixel_clock_khz = max_dvi_single_link_pixel_clock * 2;
break;
+ default:
+ return MODE_BAD;
}
/* When the display EDID claims that it's an HDMI display,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index af3d2fd61cf3..3459d356151e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -2986,10 +2986,8 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(11, 5, 1):
case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 5, 3):
- adev->family = AMDGPU_FAMILY_GC_11_5_0;
- break;
case IP_VERSION(11, 5, 4):
- adev->family = AMDGPU_FAMILY_GC_11_5_4;
+ adev->family = AMDGPU_FAMILY_GC_11_5_0;
break;
case IP_VERSION(12, 0, 0):
case IP_VERSION(12, 0, 1):
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
index 5179fa008626..19abb09f0e19 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
@@ -313,7 +313,10 @@ void amdgpu_gmc_gart_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc,
mc->gart_start = max_mc_address - mc->gart_size + 1;
break;
case AMDGPU_GART_PLACEMENT_LOW:
- mc->gart_start = 0;
+ if (size_bf >= mc->gart_size)
+ mc->gart_start = 0;
+ else
+ mc->gart_start = ALIGN(mc->fb_end, four_gb);
break;
case AMDGPU_GART_PLACEMENT_BEST_FIT:
default:
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index 7f19554b9ad1..a50c3058f97f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -873,68 +873,59 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
? -EFAULT : 0;
}
case AMDGPU_INFO_READ_MMR_REG: {
- int ret = 0;
- unsigned int n, alloc_size;
- uint32_t *regs;
unsigned int se_num = (info->read_mmr_reg.instance >>
AMDGPU_INFO_MMR_SE_INDEX_SHIFT) &
AMDGPU_INFO_MMR_SE_INDEX_MASK;
unsigned int sh_num = (info->read_mmr_reg.instance >>
AMDGPU_INFO_MMR_SH_INDEX_SHIFT) &
AMDGPU_INFO_MMR_SH_INDEX_MASK;
-
- if (!down_read_trylock(&adev->reset_domain->sem))
- return -ENOENT;
+ unsigned int alloc_size;
+ uint32_t *regs;
+ int ret;
/* set full masks if the userspace set all bits
* in the bitfields
*/
- if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) {
+ if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK)
se_num = 0xffffffff;
- } else if (se_num >= AMDGPU_GFX_MAX_SE) {
- ret = -EINVAL;
- goto out;
- }
+ else if (se_num >= AMDGPU_GFX_MAX_SE)
+ return -EINVAL;
- if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) {
+ if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK)
sh_num = 0xffffffff;
- } else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) {
- ret = -EINVAL;
- goto out;
- }
+ else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE)
+ return -EINVAL;
- if (info->read_mmr_reg.count > 128) {
- ret = -EINVAL;
- goto out;
- }
+ if (info->read_mmr_reg.count > 128)
+ return -EINVAL;
- regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), GFP_KERNEL);
- if (!regs) {
- ret = -ENOMEM;
- goto out;
- }
+ regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs),
+ GFP_KERNEL);
+ if (!regs)
+ return -ENOMEM;
+ down_read(&adev->reset_domain->sem);
alloc_size = info->read_mmr_reg.count * sizeof(*regs);
-
amdgpu_gfx_off_ctrl(adev, false);
+ ret = 0;
for (i = 0; i < info->read_mmr_reg.count; i++) {
if (amdgpu_asic_read_register(adev, se_num, sh_num,
info->read_mmr_reg.dword_offset + i,
®s[i])) {
DRM_DEBUG_KMS("unallowed offset %#x\n",
info->read_mmr_reg.dword_offset + i);
- kfree(regs);
- amdgpu_gfx_off_ctrl(adev, true);
ret = -EFAULT;
- goto out;
+ break;
}
}
amdgpu_gfx_off_ctrl(adev, true);
- n = copy_to_user(out, regs, min(size, alloc_size));
- kfree(regs);
- ret = (n ? -EFAULT : 0);
-out:
up_read(&adev->reset_domain->sem);
+
+ if (!ret) {
+ ret = copy_to_user(out, regs, min(size, alloc_size))
+ ? -EFAULT : 0;
+ }
+ kfree(regs);
return ret;
}
case AMDGPU_INFO_DEV_INFO: {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c
index 6fba9d5b29ea..ee271f43d5ad 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c
@@ -1939,7 +1939,7 @@ void amdgpu_ras_check_bad_page_status(struct amdgpu_device *adev)
if (!control || amdgpu_bad_page_threshold == 0)
return;
- if (control->ras_num_bad_pages >= ras->bad_page_cnt_threshold) {
+ if (control->ras_num_bad_pages > ras->bad_page_cnt_threshold) {
if (amdgpu_dpm_send_rma_reason(adev))
dev_warn(adev->dev, "Unable to send out-of-band RMA CPER");
else
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index 0a1b93259887..0e015741ab24 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -156,7 +156,7 @@ static void amdgpu_userq_hang_detect_work(struct work_struct *work)
struct dma_fence *fence;
struct amdgpu_userq_mgr *uq_mgr;
- if (!queue || !queue->userq_mgr)
+ if (!queue->userq_mgr)
return;
uq_mgr = queue->userq_mgr;
@@ -1231,7 +1231,7 @@ amdgpu_userq_vm_validate(struct amdgpu_userq_mgr *uq_mgr)
bo = range->bo;
ret = amdgpu_ttm_tt_get_user_pages(bo, range);
if (ret)
- goto unlock_all;
+ goto free_ranges;
}
invalidated = true;
@@ -1258,6 +1258,7 @@ amdgpu_userq_vm_validate(struct amdgpu_userq_mgr *uq_mgr)
unlock_all:
drm_exec_fini(&exec);
+free_ranges:
xa_for_each(&xa, tmp_key, range) {
if (!range)
continue;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
index 275745aa5829..1e284ecad217 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
@@ -950,11 +950,6 @@ int amdgpu_virt_init_critical_region(struct amdgpu_device *adev)
if (adev->virt.req_init_data_ver != GPU_CRIT_REGION_V2)
return 0;
- if (init_hdr_offset < 0) {
- dev_err(adev->dev, "Invalid init header offset\n");
- return -EINVAL;
- }
-
vram_size = RREG32(mmRCC_CONFIG_MEMSIZE);
if (!vram_size || vram_size == U32_MAX)
return -EINVAL;
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
index 1893ceeeb26c..8b60299b73ef 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
@@ -6752,7 +6752,7 @@ static void gfx_v10_0_gfx_mqd_set_priority(struct amdgpu_device *adev,
/* set up default queue priority level
* 0x0 = low priority, 0x1 = high priority
*/
- if (prop->hqd_pipe_priority == AMDGPU_GFX_PIPE_PRIO_HIGH)
+ if (prop->hqd_queue_priority == AMDGPU_GFX_QUEUE_PRIORITY_MAXIMUM)
priority = 1;
tmp = RREG32_SOC15(GC, 0, mmCP_GFX_HQD_QUEUE_PRIORITY);
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
index 8d73193de06f..0f783adb9335 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
@@ -4093,7 +4093,7 @@ static void gfx_v11_0_gfx_mqd_set_priority(struct amdgpu_device *adev,
/* set up default queue priority level
* 0x0 = low priority, 0x1 = high priority
*/
- if (prop->hqd_pipe_priority == AMDGPU_GFX_PIPE_PRIO_HIGH)
+ if (prop->hqd_queue_priority == AMDGPU_GFX_QUEUE_PRIORITY_MAXIMUM)
priority = 1;
tmp = regCP_GFX_HQD_QUEUE_PRIORITY_DEFAULT;
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c
index eb9725ae1607..557d15b90ad2 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c
@@ -1405,7 +1405,7 @@ static void gfx_v12_1_xcc_init_compute_vmid(struct amdgpu_device *adev,
/*
* Configure apertures:
* LDS: 0x20000000'00000000 - 0x20000001'00000000 (4GB)
- * Scratch: 0x10000000'00000000 - 0x10000001'00000000 (4GB)
+ * Scratch: 0x10000000'00000000 - 0x11ffffff'ffffffff (128PB 57-bit)
*/
sh_mem_bases = REG_SET_FIELD(0, SH_MEM_BASES, PRIVATE_BASE,
(adev->gmc.private_aperture_start >> 58));
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
index 73223d97a87f..ac90d8e9d86a 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
@@ -1571,6 +1571,71 @@ static void gfx_v6_0_setup_spi(struct amdgpu_device *adev)
mutex_unlock(&adev->grbm_idx_mutex);
}
+/**
+ * gfx_v6_0_setup_tcc() - setup which TCCs are used
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Verify whether the current GPU has any TCCs disabled,
+ * which can happen when the GPU is harvested and some
+ * memory channels are disabled, reducing the memory bus width.
+ * For example, on the Radeon HD 7870 XT (Tahiti LE).
+ *
+ * If some TCCs are disabled, we need to make sure that
+ * the disabled TCCs are not used, and the remaining TCCs
+ * are used optimally.
+ *
+ * TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels.
+ * TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used.
+ *
+ * For optimal performance:
+ * - Rely on the CHAN_STEER from the golden registers table,
+ * only skip disabled TCCs but keep the mapping order.
+ * - Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing,
+ * which performs better than using the same TCC twice.
+ */
+static void gfx_v6_0_setup_tcc(struct amdgpu_device *adev)
+{
+ u32 i, tcc, tcp_addr_config, num_active_tcc = 0;
+ u64 chan_steer, patched_chan_steer = 0;
+ const u32 num_max_tcc = adev->gfx.config.max_texture_channel_caches;
+ const u32 dis_tcc_mask =
+ amdgpu_gfx_create_bitmask(num_max_tcc) &
+ (REG_GET_FIELD(RREG32(mmCGTS_TCC_DISABLE),
+ CGTS_TCC_DISABLE, TCC_DISABLE) |
+ REG_GET_FIELD(RREG32(mmCGTS_USER_TCC_DISABLE),
+ CGTS_USER_TCC_DISABLE, TCC_DISABLE));
+
+ /* When no TCC is disabled, the golden registers table already has optimal TCC setup */
+ if (!dis_tcc_mask)
+ return;
+
+ /* Each 4-bit nibble contains the index of a TCC used by all TCPs */
+ chan_steer = RREG32(mmTCP_CHAN_STEER_LO) | ((u64)RREG32(mmTCP_CHAN_STEER_HI) << 32ull);
+
+ /* Patch the TCP to TCC mapping to skip disabled TCCs */
+ for (i = 0; i < num_max_tcc; ++i) {
+ tcc = (chan_steer >> (u64)(4 * i)) & 0xf;
+
+ if (!((1 << tcc) & dis_tcc_mask)) {
+ /* Copy enabled TCC indices to the patched register value. */
+ patched_chan_steer |= (u64)tcc << (u64)(4 * num_active_tcc);
+ ++num_active_tcc;
+ }
+ }
+
+ WARN_ON(num_active_tcc != num_max_tcc - hweight32(dis_tcc_mask));
+
+ /* Patch number of TCCs used by TCPs */
+ tcp_addr_config = REG_SET_FIELD(RREG32(mmTCP_ADDR_CONFIG),
+ TCP_ADDR_CONFIG, NUM_TCC_BANKS,
+ num_active_tcc - 1);
+
+ WREG32(mmTCP_ADDR_CONFIG, tcp_addr_config);
+ WREG32(mmTCP_CHAN_STEER_HI, upper_32_bits(patched_chan_steer));
+ WREG32(mmTCP_CHAN_STEER_LO, lower_32_bits(patched_chan_steer));
+}
+
static void gfx_v6_0_config_init(struct amdgpu_device *adev)
{
adev->gfx.config.double_offchip_lds_buf = 0;
@@ -1729,6 +1794,7 @@ static void gfx_v6_0_constants_init(struct amdgpu_device *adev)
gfx_v6_0_tiling_mode_table_init(adev);
gfx_v6_0_setup_rb(adev);
+ gfx_v6_0_setup_tcc(adev);
gfx_v6_0_setup_spi(adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c
index b9671fc39e2a..da4a0cf4aad0 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c
@@ -654,9 +654,15 @@ static int gmc_v12_0_early_init(struct amdgpu_ip_block *ip_block)
adev->gmc.shared_aperture_start = 0x2000000000000000ULL;
adev->gmc.shared_aperture_end =
adev->gmc.shared_aperture_start + (4ULL << 30) - 1;
+
adev->gmc.private_aperture_start = 0x1000000000000000ULL;
- adev->gmc.private_aperture_end =
- adev->gmc.private_aperture_start + (4ULL << 30) - 1;
+ if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(12, 1, 0))
+ adev->gmc.private_aperture_end =
+ adev->gmc.private_aperture_start + (1ULL << 57) - 1;
+ else
+ adev->gmc.private_aperture_end =
+ adev->gmc.private_aperture_start + (4ULL << 30) - 1;
+
adev->gmc.noretry_flags = AMDGPU_VM_NORETRY_FLAGS_TF;
return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c
index 9fe8d10ab270..cffb1e6bab35 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c
@@ -802,6 +802,7 @@ static const struct amd_ip_funcs jpeg_v2_0_ip_funcs = {
static const struct amdgpu_ring_funcs jpeg_v2_0_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
+ .no_user_fence = true,
.get_rptr = jpeg_v2_0_dec_ring_get_rptr,
.get_wptr = jpeg_v2_0_dec_ring_get_wptr,
.set_wptr = jpeg_v2_0_dec_ring_set_wptr,
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c
index 20983f126b49..13a6e24c624a 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c
@@ -693,6 +693,7 @@ static const struct amd_ip_funcs jpeg_v2_6_ip_funcs = {
static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
+ .no_user_fence = true,
.get_rptr = jpeg_v2_5_dec_ring_get_rptr,
.get_wptr = jpeg_v2_5_dec_ring_get_wptr,
.set_wptr = jpeg_v2_5_dec_ring_set_wptr,
@@ -724,6 +725,7 @@ static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = {
static const struct amdgpu_ring_funcs jpeg_v2_6_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
+ .no_user_fence = true,
.get_rptr = jpeg_v2_5_dec_ring_get_rptr,
.get_wptr = jpeg_v2_5_dec_ring_get_wptr,
.set_wptr = jpeg_v2_5_dec_ring_set_wptr,
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c
index 98f5e0622bc5..d0445df39d2c 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c
@@ -594,6 +594,7 @@ static const struct amd_ip_funcs jpeg_v3_0_ip_funcs = {
static const struct amdgpu_ring_funcs jpeg_v3_0_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
+ .no_user_fence = true,
.get_rptr = jpeg_v3_0_dec_ring_get_rptr,
.get_wptr = jpeg_v3_0_dec_ring_get_wptr,
.set_wptr = jpeg_v3_0_dec_ring_set_wptr,
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c
index 0bd83820dd20..6fd4238a8471 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c
@@ -759,6 +759,7 @@ static const struct amd_ip_funcs jpeg_v4_0_ip_funcs = {
static const struct amdgpu_ring_funcs jpeg_v4_0_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
+ .no_user_fence = true,
.get_rptr = jpeg_v4_0_dec_ring_get_rptr,
.get_wptr = jpeg_v4_0_dec_ring_get_wptr,
.set_wptr = jpeg_v4_0_dec_ring_set_wptr,
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
index 82abe181c730..0c746580de11 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
@@ -1219,6 +1219,7 @@ static const struct amd_ip_funcs jpeg_v4_0_3_ip_funcs = {
static const struct amdgpu_ring_funcs jpeg_v4_0_3_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
+ .no_user_fence = true,
.get_rptr = jpeg_v4_0_3_dec_ring_get_rptr,
.get_wptr = jpeg_v4_0_3_dec_ring_get_wptr,
.set_wptr = jpeg_v4_0_3_dec_ring_set_wptr,
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c
index 54fd9c800c40..a43582b9c876 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c
@@ -804,6 +804,7 @@ static const struct amd_ip_funcs jpeg_v4_0_5_ip_funcs = {
static const struct amdgpu_ring_funcs jpeg_v4_0_5_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
+ .no_user_fence = true,
.get_rptr = jpeg_v4_0_5_dec_ring_get_rptr,
.get_wptr = jpeg_v4_0_5_dec_ring_get_wptr,
.set_wptr = jpeg_v4_0_5_dec_ring_set_wptr,
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
index 46bf15dce2bd..72a4b2d0676f 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
@@ -680,6 +680,7 @@ static const struct amd_ip_funcs jpeg_v5_0_0_ip_funcs = {
static const struct amdgpu_ring_funcs jpeg_v5_0_0_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
+ .no_user_fence = true,
.get_rptr = jpeg_v5_0_0_dec_ring_get_rptr,
.get_wptr = jpeg_v5_0_0_dec_ring_get_wptr,
.set_wptr = jpeg_v5_0_0_dec_ring_set_wptr,
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c
index edecbfe66c79..250316704dfa 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c
@@ -884,6 +884,7 @@ static const struct amd_ip_funcs jpeg_v5_0_1_ip_funcs = {
static const struct amdgpu_ring_funcs jpeg_v5_0_1_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
+ .no_user_fence = true,
.get_rptr = jpeg_v5_0_1_dec_ring_get_rptr,
.get_wptr = jpeg_v5_0_1_dec_ring_get_wptr,
.set_wptr = jpeg_v5_0_1_dec_ring_set_wptr,
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_3_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_3_0.c
index 1821dced936f..e7546816baba 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_3_0.c
@@ -661,6 +661,7 @@ static const struct amd_ip_funcs jpeg_v5_3_0_ip_funcs = {
static const struct amdgpu_ring_funcs jpeg_v5_3_0_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
+ .no_user_fence = true,
.get_rptr = jpeg_v5_3_0_dec_ring_get_rptr,
.get_wptr = jpeg_v5_3_0_dec_ring_get_wptr,
.set_wptr = jpeg_v5_3_0_dec_ring_set_wptr,
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c
index fea576a7f397..efb3fde919ee 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c
@@ -242,6 +242,10 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev)
uint64_t addr;
uint32_t size;
+ /* When the keyselect is already set, don't perturb it. */
+ if (RREG32(mmUVD_FW_START))
+ return;
+
/* program the VCPU memory controller bits 0-27 */
addr = (adev->uvd.inst->gpu_addr + AMDGPU_UVD_FIRMWARE_OFFSET) >> 3;
size = AMDGPU_UVD_FIRMWARE_SIZE(adev) >> 3;
@@ -284,6 +288,12 @@ static int uvd_v3_1_fw_validate(struct amdgpu_device *adev)
int i;
uint32_t keysel = adev->uvd.keyselect;
+ if (RREG32(mmUVD_FW_START) & UVD_FW_STATUS__PASS_MASK) {
+ dev_dbg(adev->dev, "UVD keyselect already set: 0x%x (on CPU: 0x%x)\n",
+ RREG32(mmUVD_FW_START), adev->uvd.keyselect);
+ return 0;
+ }
+
WREG32(mmUVD_FW_START, keysel);
for (i = 0; i < 10; ++i) {
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
index 73ce3d211ed6..8a9ba2276275 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
@@ -93,6 +93,11 @@ static void uvd_v4_2_ring_set_wptr(struct amdgpu_ring *ring)
static int uvd_v4_2_early_init(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
+
+ /* UVD doesn't work without DPM, it needs DPM to ungate it. */
+ if (!amdgpu_dpm)
+ return -ENOENT;
+
adev->uvd.num_uvd_inst = 1;
uvd_v4_2_set_ring_funcs(adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
index e35fae9cdaf6..0442bfcfd384 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
@@ -2113,6 +2113,7 @@ static const struct amd_ip_funcs vcn_v2_0_ip_funcs = {
static const struct amdgpu_ring_funcs vcn_v2_0_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_DEC,
.align_mask = 0xf,
+ .no_user_fence = true,
.secure_submission_supported = true,
.get_rptr = vcn_v2_0_dec_ring_get_rptr,
.get_wptr = vcn_v2_0_dec_ring_get_wptr,
@@ -2145,6 +2146,7 @@ static const struct amdgpu_ring_funcs vcn_v2_0_enc_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_ENC,
.align_mask = 0x3f,
.nop = VCN_ENC_CMD_NO_OP,
+ .no_user_fence = true,
.get_rptr = vcn_v2_0_enc_ring_get_rptr,
.get_wptr = vcn_v2_0_enc_ring_get_wptr,
.set_wptr = vcn_v2_0_enc_ring_set_wptr,
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
index 006a15451197..8b8184fe6764 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
@@ -1778,6 +1778,7 @@ static void vcn_v2_5_dec_ring_set_wptr(struct amdgpu_ring *ring)
static const struct amdgpu_ring_funcs vcn_v2_5_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_DEC,
.align_mask = 0xf,
+ .no_user_fence = true,
.secure_submission_supported = true,
.get_rptr = vcn_v2_5_dec_ring_get_rptr,
.get_wptr = vcn_v2_5_dec_ring_get_wptr,
@@ -1879,6 +1880,7 @@ static const struct amdgpu_ring_funcs vcn_v2_5_enc_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_ENC,
.align_mask = 0x3f,
.nop = VCN_ENC_CMD_NO_OP,
+ .no_user_fence = true,
.get_rptr = vcn_v2_5_enc_ring_get_rptr,
.get_wptr = vcn_v2_5_enc_ring_get_wptr,
.set_wptr = vcn_v2_5_enc_ring_set_wptr,
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
index 2fe5b3fe287f..81bba3ec2a93 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
@@ -1856,6 +1856,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_dec_sw_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_DEC,
.align_mask = 0x3f,
.nop = VCN_DEC_SW_CMD_NO_OP,
+ .no_user_fence = true,
.secure_submission_supported = true,
.get_rptr = vcn_v3_0_dec_ring_get_rptr,
.get_wptr = vcn_v3_0_dec_ring_get_wptr,
@@ -2038,6 +2039,7 @@ static int vcn_v3_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
static const struct amdgpu_ring_funcs vcn_v3_0_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_DEC,
.align_mask = 0xf,
+ .no_user_fence = true,
.secure_submission_supported = true,
.get_rptr = vcn_v3_0_dec_ring_get_rptr,
.get_wptr = vcn_v3_0_dec_ring_get_wptr,
@@ -2140,6 +2142,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_enc_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_ENC,
.align_mask = 0x3f,
.nop = VCN_ENC_CMD_NO_OP,
+ .no_user_fence = true,
.get_rptr = vcn_v3_0_enc_ring_get_rptr,
.get_wptr = vcn_v3_0_enc_ring_get_wptr,
.set_wptr = vcn_v3_0_enc_ring_set_wptr,
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
index 63d37b475c2c..ff7269bafae8 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
@@ -1996,6 +1996,7 @@ static struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_ENC,
.align_mask = 0x3f,
.nop = VCN_ENC_CMD_NO_OP,
+ .no_user_fence = true,
.extra_bytes = sizeof(struct amdgpu_vcn_rb_metadata),
.get_rptr = vcn_v4_0_unified_ring_get_rptr,
.get_wptr = vcn_v4_0_unified_ring_get_wptr,
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
index e78526a4e521..210e41cf2937 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
@@ -1758,6 +1758,7 @@ static const struct amdgpu_ring_funcs vcn_v4_0_3_unified_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_ENC,
.align_mask = 0x3f,
.nop = VCN_ENC_CMD_NO_OP,
+ .no_user_fence = true,
.get_rptr = vcn_v4_0_3_unified_ring_get_rptr,
.get_wptr = vcn_v4_0_3_unified_ring_get_wptr,
.set_wptr = vcn_v4_0_3_unified_ring_set_wptr,
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
index 1f6a22983c0d..1571cc5a148c 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
@@ -1483,6 +1483,7 @@ static struct amdgpu_ring_funcs vcn_v4_0_5_unified_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_ENC,
.align_mask = 0x3f,
.nop = VCN_ENC_CMD_NO_OP,
+ .no_user_fence = true,
.get_rptr = vcn_v4_0_5_unified_ring_get_rptr,
.get_wptr = vcn_v4_0_5_unified_ring_get_wptr,
.set_wptr = vcn_v4_0_5_unified_ring_set_wptr,
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
index 6109124f852e..d5f49fa33bee 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
@@ -1207,6 +1207,7 @@ static const struct amdgpu_ring_funcs vcn_v5_0_0_unified_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_ENC,
.align_mask = 0x3f,
.nop = VCN_ENC_CMD_NO_OP,
+ .no_user_fence = true,
.get_rptr = vcn_v5_0_0_unified_ring_get_rptr,
.get_wptr = vcn_v5_0_0_unified_ring_get_wptr,
.set_wptr = vcn_v5_0_0_unified_ring_set_wptr,
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c
index c28c6aff17aa..54fbf8d73ca6 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c
@@ -1419,6 +1419,7 @@ static const struct amdgpu_ring_funcs vcn_v5_0_1_unified_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_ENC,
.align_mask = 0x3f,
.nop = VCN_ENC_CMD_NO_OP,
+ .no_user_fence = true,
.get_rptr = vcn_v5_0_1_unified_ring_get_rptr,
.get_wptr = vcn_v5_0_1_unified_ring_get_wptr,
.set_wptr = vcn_v5_0_1_unified_ring_set_wptr,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c
index e8da0b4527dc..04c5e26f01ed 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c
@@ -342,20 +342,14 @@ static void kfd_init_apertures_vi(struct kfd_process_device *pdd, uint8_t id)
static void kfd_init_apertures_v9(struct kfd_process_device *pdd, uint8_t id)
{
- if (KFD_GC_VERSION(pdd->dev) >= IP_VERSION(12, 1, 0))
- pdd->lds_base = pdd->dev->adev->gmc.shared_aperture_start;
- else
- pdd->lds_base = MAKE_LDS_APP_BASE_V9();
+ pdd->lds_base = MAKE_LDS_APP_BASE_V9();
pdd->lds_limit = MAKE_LDS_APP_LIMIT(pdd->lds_base);
pdd->gpuvm_base = AMDGPU_VA_RESERVED_BOTTOM;
pdd->gpuvm_limit =
pdd->dev->kfd->shared_resources.gpuvm_size - 1;
- if (KFD_GC_VERSION(pdd->dev) >= IP_VERSION(12, 1, 0))
- pdd->scratch_base = pdd->dev->adev->gmc.private_aperture_start;
- else
- pdd->scratch_base = MAKE_SCRATCH_APP_BASE_V9();
+ pdd->scratch_base = MAKE_SCRATCH_APP_BASE_V9();
pdd->scratch_limit = MAKE_SCRATCH_APP_LIMIT(pdd->scratch_base);
/*
@@ -365,6 +359,25 @@ static void kfd_init_apertures_v9(struct kfd_process_device *pdd, uint8_t id)
pdd->qpd.cwsr_base = AMDGPU_VA_RESERVED_TRAP_START(pdd->dev->adev);
}
+static void kfd_init_apertures_v12(struct kfd_process_device *pdd, uint8_t id)
+{
+ pdd->lds_base = pdd->dev->adev->gmc.shared_aperture_start;
+ pdd->lds_limit = pdd->dev->adev->gmc.shared_aperture_end;
+
+ pdd->gpuvm_base = AMDGPU_VA_RESERVED_BOTTOM;
+ pdd->gpuvm_limit =
+ pdd->dev->kfd->shared_resources.gpuvm_size - 1;
+
+ pdd->scratch_base = pdd->dev->adev->gmc.private_aperture_start;
+ pdd->scratch_limit = pdd->dev->adev->gmc.private_aperture_end;
+
+ /*
+ * Place TBA/TMA on opposite side of VM hole to prevent
+ * stray faults from triggering SVM on these pages.
+ */
+ pdd->qpd.cwsr_base = AMDGPU_VA_RESERVED_TRAP_START(pdd->dev->adev);
+}
+
int kfd_init_apertures(struct kfd_process *process)
{
uint8_t id = 0;
@@ -412,9 +425,11 @@ int kfd_init_apertures(struct kfd_process *process)
kfd_init_apertures_vi(pdd, id);
break;
default:
- if (KFD_GC_VERSION(dev) >= IP_VERSION(9, 0, 1))
+ if (KFD_GC_VERSION(dev) >= IP_VERSION(12, 1, 0)) {
+ kfd_init_apertures_v12(pdd, id);
+ } else if (KFD_GC_VERSION(dev) >= IP_VERSION(9, 0, 1)) {
kfd_init_apertures_v9(pdd, id);
- else {
+ } else {
WARN(1, "Unexpected ASIC family %u",
dev->adev->asic_type);
return -EINVAL;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c
index 562d475cf4c9..bb70e57ae4d5 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c
@@ -70,7 +70,6 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd,
static void set_priority(struct cik_mqd *m, struct queue_properties *q)
{
m->cp_hqd_pipe_priority = pipe_priority_map[q->priority];
- /* m->cp_hqd_queue_priority = q->priority; */
}
static struct kfd_mem_obj *allocate_mqd(struct mqd_manager *mm,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c
index d6067316d7f4..77fb41e2486a 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c
@@ -70,7 +70,6 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd,
static void set_priority(struct v10_compute_mqd *m, struct queue_properties *q)
{
m->cp_hqd_pipe_priority = pipe_priority_map[q->priority];
- /* m->cp_hqd_queue_priority = q->priority; */
}
static struct kfd_mem_obj *allocate_mqd(struct mqd_manager *mm,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
index e3a7acb0ccbc..a1e3cf2384dd 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
@@ -96,7 +96,6 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd,
static void set_priority(struct v11_compute_mqd *m, struct queue_properties *q)
{
m->cp_hqd_pipe_priority = pipe_priority_map[q->priority];
- /* m->cp_hqd_queue_priority = q->priority; */
}
static struct kfd_mem_obj *allocate_mqd(struct mqd_manager *mm,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c
index 0b97376fc6f9..b3e122d7876e 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c
@@ -77,7 +77,6 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd,
static void set_priority(struct v12_compute_mqd *m, struct queue_properties *q)
{
m->cp_hqd_pipe_priority = pipe_priority_map[q->priority];
- /* m->cp_hqd_queue_priority = q->priority; */
}
static struct kfd_mem_obj *allocate_mqd(struct mqd_manager *mm,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c
index eef6bdce4be3..c90c0d99b1e3 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c
@@ -131,7 +131,6 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd,
static void set_priority(struct v12_1_compute_mqd *m, struct queue_properties *q)
{
m->cp_hqd_pipe_priority = pipe_priority_map[q->priority];
- /* m->cp_hqd_queue_priority = q->priority; */
}
static struct kfd_mem_obj *allocate_mqd(struct mqd_manager *mm,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
index a535f151cb5f..e856bee62805 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
@@ -113,7 +113,6 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd,
static void set_priority(struct v9_mqd *m, struct queue_properties *q)
{
m->cp_hqd_pipe_priority = pipe_priority_map[q->priority];
- /* m->cp_hqd_queue_priority = q->priority; */
}
static bool mqd_on_vram(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
index 69c1b8a690b8..f02ef2d44a07 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
@@ -73,7 +73,6 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd,
static void set_priority(struct vi_mqd *m, struct queue_properties *q)
{
m->cp_hqd_pipe_priority = pipe_priority_map[q->priority];
- /* m->cp_hqd_queue_priority = q->priority; */
}
static struct kfd_mem_obj *allocate_mqd(struct mqd_manager *mm,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
index f5d2847e1cbb..3d172e35e57c 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
@@ -590,7 +590,8 @@ int pqm_update_queue_properties(struct process_queue_manager *pqm,
return err;
if (kfd_queue_buffer_get(vm, (void *)p->queue_address, &p->ring_bo,
- p->queue_size)) {
+ p->queue_size +
+ pqn->q->properties.metadata_queue_size)) {
pr_debug("ring buf 0x%llx size 0x%llx not mapped on GPU\n",
p->queue_address, p->queue_size);
amdgpu_bo_unreserve(vm->root.bo);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 2328c1aa0ead..0aee65503642 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -1891,7 +1891,11 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
goto error;
}
- init_data.asic_id.chip_family = adev->family;
+ /* special handling for early revisions of GC 11.5.4 */
+ if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 4))
+ init_data.asic_id.chip_family = AMDGPU_FAMILY_GC_11_5_4;
+ else
+ init_data.asic_id.chip_family = adev->family;
init_data.asic_id.pci_revision_id = adev->pdev->revision;
init_data.asic_id.hw_internal_rev = adev->external_rev_id;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index 304437c2284d..527d0ad69348 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -101,23 +101,22 @@ bool amdgpu_dm_crtc_vrr_active(const struct dm_crtc_state *dm_state)
/**
* amdgpu_dm_crtc_set_panel_sr_feature() - Manage panel self-refresh features.
- *
- * @vblank_work: is a pointer to a struct vblank_control_work object.
- * @vblank_enabled: indicates whether the DRM vblank counter is currently
- * enabled (true) or disabled (false).
- * @allow_sr_entry: represents whether entry into the self-refresh mode is
- * allowed (true) or not allowed (false).
+ * @dm: amdgpu display manager instance.
+ * @acrtc: CRTC whose panel self-refresh state is being updated.
+ * @stream: DC stream associated with @acrtc.
+ * @vblank_enabled: Whether the DRM vblank counter is currently enabled.
+ * @allow_sr_entry: Whether entry into self-refresh mode is allowed.
*
* The DRM vblank counter enable/disable action is used as the trigger to enable
* or disable various panel self-refresh features:
*
* Panel Replay and PSR SU
* - Enable when:
- * - VRR is disabled
- * - vblank counter is disabled
- * - entry is allowed: usermode demonstrates an adequate number of fast
- * commits)
- * - CRC capture window isn't active
+ * - VRR is disabled
+ * - vblank counter is disabled
+ * - entry is allowed: usermode demonstrates an adequate number of fast
+ * commits
+ * - CRC capture window isn't active
* - Keep enabled even when vblank counter gets enabled
*
* PSR1
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index a09761f9882d..5b0245eb5fdb 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -993,6 +993,45 @@ dm_helpers_read_acpi_edid(struct amdgpu_dm_connector *aconnector)
return drm_edid_read_custom(connector, dm_helpers_probe_acpi_edid, connector);
}
+static const struct drm_edid *
+dm_helpers_read_vbios_hardcoded_edid(struct dc_link *link, struct amdgpu_dm_connector *aconnector)
+{
+ struct dc_bios *bios = link->ctx->dc_bios;
+ struct embedded_panel_info info;
+ const struct drm_edid *edid;
+ enum bp_result r;
+
+ if (!dc_is_embedded_signal(link->connector_signal) ||
+ !bios->funcs->get_embedded_panel_info)
+ return NULL;
+
+ memset(&info, 0, sizeof(info));
+ r = bios->funcs->get_embedded_panel_info(bios, &info);
+
+ if (r != BP_RESULT_OK) {
+ dm_error("Error when reading embedded panel info: %u\n", r);
+ return NULL;
+ }
+
+ if (!info.fake_edid || !info.fake_edid_size) {
+ dm_error("Embedded panel info doesn't contain an EDID\n");
+ return NULL;
+ }
+
+ edid = drm_edid_alloc(info.fake_edid, info.fake_edid_size);
+
+ if (!drm_edid_valid(edid)) {
+ dm_error("EDID from embedded panel info is invalid\n");
+ drm_edid_free(edid);
+ return NULL;
+ }
+
+ aconnector->base.display_info.width_mm = info.panel_width_mm;
+ aconnector->base.display_info.height_mm = info.panel_height_mm;
+
+ return edid;
+}
+
void populate_hdmi_info_from_connector(struct drm_hdmi_info *hdmi, struct dc_edid_caps *edid_caps)
{
edid_caps->scdc_present = hdmi->scdc.supported;
@@ -1013,6 +1052,9 @@ enum dc_edid_status dm_helpers_read_local_edid(
if (link->aux_mode)
ddc = &aconnector->dm_dp_aux.aux.ddc;
+ else if (link->ddc_hw_inst == GPIO_DDC_LINE_UNKNOWN &&
+ dc_is_embedded_signal(link->connector_signal))
+ ddc = NULL;
else
ddc = &aconnector->i2c->base;
@@ -1023,6 +1065,8 @@ enum dc_edid_status dm_helpers_read_local_edid(
drm_edid = dm_helpers_read_acpi_edid(aconnector);
if (drm_edid)
drm_info(connector->dev, "Using ACPI provided EDID for %s\n", connector->name);
+ else if (!ddc)
+ drm_edid = dm_helpers_read_vbios_hardcoded_edid(link, aconnector);
else
drm_edid = drm_edid_read_ddc(connector, ddc);
drm_edid_connector_update(connector, drm_edid);
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
index 73e3c45eeeba..bbd8d52330b5 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
@@ -1295,6 +1295,60 @@ static enum bp_result bios_parser_get_embedded_panel_info(
return BP_RESULT_FAILURE;
}
+static enum bp_result get_embedded_panel_extra_info(
+ struct bios_parser *bp,
+ struct embedded_panel_info *info,
+ const uint32_t table_offset)
+{
+ uint8_t *record = bios_get_image(&bp->base, table_offset, 1);
+ ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record;
+ ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record;
+
+ while (*record != ATOM_RECORD_END_TYPE) {
+ switch (*record) {
+ case LCD_MODE_PATCH_RECORD_MODE_TYPE:
+ record += sizeof(ATOM_PATCH_RECORD_MODE);
+ break;
+ case LCD_RTS_RECORD_TYPE:
+ record += sizeof(ATOM_LCD_RTS_RECORD);
+ break;
+ case LCD_CAP_RECORD_TYPE:
+ record += sizeof(ATOM_LCD_MODE_CONTROL_CAP);
+ break;
+ case LCD_FAKE_EDID_PATCH_RECORD_TYPE:
+ fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record;
+ if (fake_edid_record->ucFakeEDIDLength) {
+ if (fake_edid_record->ucFakeEDIDLength == 128)
+ info->fake_edid_size =
+ fake_edid_record->ucFakeEDIDLength;
+ else
+ info->fake_edid_size =
+ fake_edid_record->ucFakeEDIDLength * 128;
+
+ info->fake_edid = fake_edid_record->ucFakeEDIDString;
+
+ record += struct_size(fake_edid_record,
+ ucFakeEDIDString,
+ info->fake_edid_size);
+ } else {
+ /* empty fake edid record must be 3 bytes long */
+ record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1;
+ }
+ break;
+ case LCD_PANEL_RESOLUTION_RECORD_TYPE:
+ panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record;
+ info->panel_width_mm = panel_res_record->usHSize;
+ info->panel_height_mm = panel_res_record->usVSize;
+ record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD);
+ break;
+ default:
+ return BP_RESULT_BADBIOSTABLE;
+ }
+ }
+
+ return BP_RESULT_OK;
+}
+
static enum bp_result get_embedded_panel_info_v1_2(
struct bios_parser *bp,
struct embedded_panel_info *info)
@@ -1411,6 +1465,10 @@ static enum bp_result get_embedded_panel_info_v1_2(
if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc)
info->lcd_timing.misc_info.API_ENABLED = true;
+ if (lvds->usExtInfoTableOffset)
+ return get_embedded_panel_extra_info(bp, info,
+ le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info));
+
return BP_RESULT_OK;
}
@@ -1536,6 +1594,10 @@ static enum bp_result get_embedded_panel_info_v1_3(
(uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL &
lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT;
+ if (lvds->usExtInfoTableOffset)
+ return get_embedded_panel_extra_info(bp, info,
+ le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info));
+
return BP_RESULT_OK;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 4c4239cac863..8044c80971f0 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -1638,7 +1638,7 @@ struct dc_scratch_space {
struct dc_link_training_overrides preferred_training_settings;
struct dp_audio_test_data audio_test_data;
- uint8_t ddc_hw_inst;
+ enum gpio_ddc_line ddc_hw_inst;
uint8_t hpd_src;
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
index b15360bcdacf..b3cedaa596c0 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
@@ -958,7 +958,10 @@ void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv)
{
uint32_t i;
- if (!dc_dmub_srv || !dc_dmub_srv->dmub) {
+ if (!dc_dmub_srv)
+ return;
+
+ if (!dc_dmub_srv->dmub) {
DC_LOG_ERROR("%s: invalid parameters.", __func__);
return;
}
@@ -1163,7 +1166,10 @@ void dc_dmub_srv_enable_dpia_trace(const struct dc *dc)
{
struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv;
- if (!dc_dmub_srv || !dc_dmub_srv->dmub) {
+ if (!dc_dmub_srv)
+ return;
+
+ if (!dc_dmub_srv->dmub) {
DC_LOG_ERROR("%s: invalid parameters.", __func__);
return;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
index 2ba3d3a3aac5..d2b36cfb28c3 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
@@ -1071,7 +1071,9 @@ void dce110_link_encoder_hw_init(
ASSERT(result == BP_RESULT_OK);
}
- aux_initialize(enc110);
+
+ if (enc110->aux_regs)
+ aux_initialize(enc110);
/* reinitialize HPD.
* hpd_initialize() will pass DIG_FE id to HW context.
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c
index a2c46350e44e..95f8b7c7d657 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c
+++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c
@@ -646,6 +646,9 @@ enum gpio_result dal_ddc_change_mode(
enum gpio_ddc_line dal_ddc_get_line(
const struct ddc *ddc)
{
+ if (!ddc)
+ return GPIO_DDC_LINE_UNKNOWN;
+
return (enum gpio_ddc_line)dal_gpio_get_enum(ddc->pin_data);
}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c
index 21815ad01a29..409cc6e6cd84 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c
@@ -549,7 +549,9 @@ static bool construct_phy(struct dc_link *link,
goto ddc_create_fail;
}
- if (!link->ddc->ddc_pin) {
+ /* Embedded display connectors such as LVDS may not have DDC. */
+ if (!link->ddc->ddc_pin &&
+ !dc_is_embedded_signal(link->connector_signal)) {
DC_ERROR("Failed to get I2C info for connector!\n");
goto ddc_create_fail;
}
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c
index 3d52973dd7f2..15f220671fbe 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c
@@ -753,7 +753,8 @@ static struct link_encoder *dce60_link_encoder_create(
enc_init_data,
&link_enc_feature,
&link_enc_regs[link_regs_id],
- &link_enc_aux_regs[enc_init_data->channel - 1],
+ enc_init_data->channel == CHANNEL_ID_UNKNOWN ?
+ NULL : &link_enc_aux_regs[enc_init_data->channel - 1],
enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ?
NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);
return &enc110->base;
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c
index 89927727a0d9..42d0bd656f79 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c
@@ -759,7 +759,8 @@ static struct link_encoder *dce80_link_encoder_create(
enc_init_data,
&link_enc_feature,
&link_enc_regs[link_regs_id],
- &link_enc_aux_regs[enc_init_data->channel - 1],
+ enc_init_data->channel == CHANNEL_ID_UNKNOWN ?
+ NULL : &link_enc_aux_regs[enc_init_data->channel - 1],
enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ?
NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);
return &enc110->base;
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
index c3a6ae14de18..43b72b9113be 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
@@ -92,9 +92,14 @@
#include "dml/dcn32/dcn32_fpu.h"
#include "dc_state_priv.h"
+#include "dc_fpu.h"
#include "dml2_0/dml2_wrapper.h"
+#if !defined(DC_RUN_WITH_PREEMPTION_ENABLED)
+#define DC_RUN_WITH_PREEMPTION_ENABLED(code) code
+#endif
+
#define DC_LOGGER_INIT(logger)
enum dcn32_clk_src_array_id {
@@ -1684,7 +1689,8 @@ static void dcn32_enable_phantom_plane(struct dc *dc,
if (curr_pipe->top_pipe && curr_pipe->top_pipe->plane_state == curr_pipe->plane_state)
phantom_plane = prev_phantom_plane;
else
- phantom_plane = dc_state_create_phantom_plane(dc, context, curr_pipe->plane_state);
+ DC_RUN_WITH_PREEMPTION_ENABLED(phantom_plane =
+ dc_state_create_phantom_plane(dc, context, curr_pipe->plane_state));
if (!phantom_plane)
continue;
diff --git a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h
index 38a77fa9b4af..a0f03fb67605 100644
--- a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h
+++ b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h
@@ -153,6 +153,10 @@ struct embedded_panel_info {
uint32_t drr_enabled;
uint32_t min_drr_refresh_rate;
bool realtek_eDPToLVDS;
+ uint16_t panel_width_mm;
+ uint16_t panel_height_mm;
+ uint16_t fake_edid_size;
+ const uint8_t *fake_edid;
};
struct dc_firmware_info {
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c
index 2b5ac21fee39..1d6e30269d56 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c
@@ -104,6 +104,21 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr)
PP_GFXOFF_MASK);
hwmgr->pp_table_version = PP_TABLE_V0;
hwmgr->od_enabled = false;
+ switch (hwmgr->chip_id) {
+ case CHIP_BONAIRE:
+ /* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM
+ * R7 260X cards with old MC ucode: MCLK DPM is unstable
+ */
+ if (adev->pdev->subsystem_vendor == 0x106B ||
+ adev->pdev->device == 0x6658) {
+ dev_info(adev->dev, "disabling MCLK DPM on quirky ASIC");
+ adev->pm.pp_feature &= ~PP_MCLK_DPM_MASK;
+ hwmgr->feature_mask &= ~PP_MCLK_DPM_MASK;
+ }
+ break;
+ default:
+ break;
+ }
smu7_init_function_pointers(hwmgr);
break;
case AMDGPU_FAMILY_CZ:
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
index e38222877f7e..bc6acdb52c26 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
@@ -787,7 +787,7 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr)
hwmgr->dyn_state.vddc_dependency_on_mclk;
struct phm_cac_leakage_table *std_voltage_table =
hwmgr->dyn_state.cac_leakage_table;
- uint32_t i;
+ uint32_t i, clk;
PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL,
"SCLK dependency table is missing. This table is mandatory", return -EINVAL);
@@ -804,10 +804,12 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr)
data->dpm_table.sclk_table.count = 0;
for (i = 0; i < allowed_vdd_sclk_table->count; i++) {
+ clk = min(allowed_vdd_sclk_table->entries[i].clk, data->sclk_cap);
+
if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value !=
- allowed_vdd_sclk_table->entries[i].clk) {
+ clk) {
data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value =
- allowed_vdd_sclk_table->entries[i].clk;
+ clk;
data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = (i == 0) ? 1 : 0;
data->dpm_table.sclk_table.count++;
}
@@ -2802,6 +2804,10 @@ static int smu7_patch_dependency_tables_with_leakage(struct pp_hwmgr *hwmgr)
if (tmp)
return -EINVAL;
+ tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dependency_on_display_clock);
+ if (tmp)
+ return -EINVAL;
+
tmp = smu7_patch_vce_vddc(hwmgr, hwmgr->dyn_state.vce_clock_voltage_dependency_table);
if (tmp)
return -EINVAL;
@@ -2885,6 +2891,8 @@ static int smu7_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
{
kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
+ kfree(hwmgr->dyn_state.vddc_dependency_on_display_clock);
+ hwmgr->dyn_state.vddc_dependency_on_display_clock = NULL;
kfree(hwmgr->backend);
hwmgr->backend = NULL;
@@ -2955,6 +2963,70 @@ static int smu7_update_edc_leakage_table(struct pp_hwmgr *hwmgr)
return ret;
}
+static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr *hwmgr)
+{
+ struct phm_clock_voltage_dependency_table *table;
+
+ if (!amdgpu_device_ip_get_ip_block(hwmgr->adev, AMD_IP_BLOCK_TYPE_DCE))
+ return 0;
+
+ table = kzalloc(struct_size(table, entries, 4), GFP_KERNEL);
+ if (!table)
+ return -ENOMEM;
+
+ if (hwmgr->chip_id >= CHIP_POLARIS10) {
+ table->entries[0].clk = 38918;
+ table->entries[1].clk = 45900;
+ table->entries[2].clk = 66700;
+ table->entries[3].clk = 113200;
+
+ table->entries[0].v = 700;
+ table->entries[1].v = 740;
+ table->entries[2].v = 800;
+ table->entries[3].v = 900;
+ } else {
+ if (hwmgr->chip_family == AMDGPU_FAMILY_CZ) {
+ table->entries[0].clk = 35200;
+ table->entries[1].clk = 35200;
+ table->entries[2].clk = 46700;
+ table->entries[3].clk = 64300;
+ } else {
+ table->entries[0].clk = 0;
+ table->entries[1].clk = 35200;
+ table->entries[2].clk = 54000;
+ table->entries[3].clk = 62500;
+ }
+
+ table->entries[0].v = 0;
+ table->entries[1].v = 720;
+ table->entries[2].v = 810;
+ table->entries[3].v = 900;
+ }
+
+ table->count = 4;
+ hwmgr->dyn_state.vddc_dependency_on_display_clock = table;
+ return 0;
+}
+
+static void smu7_set_sclk_cap(struct pp_hwmgr *hwmgr)
+{
+ struct amdgpu_device *adev = hwmgr->adev;
+ struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+ data->sclk_cap = 0xffffffff;
+
+ if (hwmgr->od_enabled)
+ return;
+
+ /* R9 390X board: last sclk dpm level is unstable, use lower sclk */
+ if (adev->pdev->device == 0x67B0 &&
+ adev->pdev->subsystem_vendor == 0x1043)
+ data->sclk_cap = 104000; /* 1040 MHz */
+
+ if (data->sclk_cap != 0xffffffff)
+ dev_info(adev->dev, "sclk cap: %u kHz on quirky ASIC\n", data->sclk_cap * 10);
+}
+
static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
{
struct amdgpu_device *adev = hwmgr->adev;
@@ -2966,6 +3038,7 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
return -ENOMEM;
hwmgr->backend = data;
+ smu7_set_sclk_cap(hwmgr);
smu7_patch_voltage_workaround(hwmgr);
smu7_init_dpm_defaults(hwmgr);
@@ -2983,6 +3056,10 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
smu7_get_elb_voltages(hwmgr);
}
+ result = smu7_init_voltage_dependency_on_display_clock_table(hwmgr);
+ if (result)
+ goto fail;
+
if (hwmgr->pp_table_version == PP_TABLE_V1) {
smu7_complete_dependency_tables(hwmgr);
smu7_set_private_data_based_on_pptable_v1(hwmgr);
@@ -3079,13 +3156,40 @@ static int smu7_force_dpm_highest(struct pp_hwmgr *hwmgr)
return 0;
}
+static uint32_t smu7_lookup_vddc_from_dispclk(struct pp_hwmgr *hwmgr)
+{
+ const struct amd_pp_display_configuration *cfg = hwmgr->display_config;
+ const struct phm_clock_voltage_dependency_table *vddc_dep_on_dispclk =
+ hwmgr->dyn_state.vddc_dependency_on_display_clock;
+ uint32_t i;
+
+ if (!vddc_dep_on_dispclk || !vddc_dep_on_dispclk->count ||
+ !cfg || !cfg->num_display || !cfg->display_clk)
+ return 0;
+
+ /* Start from 1 because ClocksStateUltraLow should not be used according to DC. */
+ for (i = 1; i < vddc_dep_on_dispclk->count; ++i)
+ if (vddc_dep_on_dispclk->entries[i].clk >= cfg->display_clk)
+ return vddc_dep_on_dispclk->entries[i].v;
+
+ return vddc_dep_on_dispclk->entries[vddc_dep_on_dispclk->count - 1].v;
+}
+
+static void smu7_apply_minimum_dce_voltage_request(struct pp_hwmgr *hwmgr)
+{
+ uint32_t req_vddc = smu7_lookup_vddc_from_dispclk(hwmgr);
+
+ smum_send_msg_to_smc_with_parameter(hwmgr,
+ PPSMC_MSG_VddC_Request,
+ req_vddc * VOLTAGE_SCALE,
+ NULL);
+}
+
static int smu7_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr)
{
struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
- if (hwmgr->pp_table_version == PP_TABLE_V1)
- phm_apply_dal_min_voltage_request(hwmgr);
-/* TO DO for v0 iceland and Ci*/
+ smu7_apply_minimum_dce_voltage_request(hwmgr);
if (!data->sclk_dpm_key_disabled) {
if (data->dpm_level_enable_mask.sclk_dpm_enable_mask)
@@ -3821,7 +3925,7 @@ static int smu7_get_pp_table_entry_callback_func_v0(struct pp_hwmgr *hwmgr,
/* Performance levels are arranged from low to high. */
performance_level->memory_clock = memory_clock;
- performance_level->engine_clock = engine_clock;
+ performance_level->engine_clock = min(engine_clock, data->sclk_cap);
pcie_gen_from_bios = visland_clk_info->ucPCIEGen;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h
index d9e8b386bd4d..66adabeab6a3 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h
@@ -234,6 +234,7 @@ struct smu7_hwmgr {
uint32_t pcie_gen_cap;
uint32_t pcie_lane_cap;
uint32_t pcie_spc_cap;
+ uint32_t sclk_cap;
struct smu7_leakage_voltage vddc_leakage;
struct smu7_leakage_voltage vddci_leakage;
struct smu7_leakage_voltage vddcgfx_leakage;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h
index c661185753b4..2f49c95342a1 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h
+++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h
@@ -631,6 +631,7 @@ struct phm_dynamic_state_info {
struct phm_clock_voltage_dependency_table *vddci_dependency_on_mclk;
struct phm_clock_voltage_dependency_table *vddc_dependency_on_mclk;
struct phm_clock_voltage_dependency_table *mvdd_dependency_on_mclk;
+ struct phm_clock_voltage_dependency_table *vddc_dependency_on_display_clock;
struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl;
struct phm_clock_array *valid_sclk_values;
struct phm_clock_array *valid_mclk_values;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c
index 7d5df18db8d2..3650e7beeb67 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c
@@ -245,7 +245,7 @@ static void ci_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
smu_data->power_tune_defaults = &defaults_hawaii_pro;
break;
case 0x67B8:
- case 0x66B0:
+ case 0x67B0:
smu_data->power_tune_defaults = &defaults_hawaii_xt;
break;
case 0x6640:
@@ -543,12 +543,11 @@ static int ci_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
{
struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults;
- uint32_t temp;
if (ci_read_smc_sram_dword(hwmgr,
fuse_table_offset +
offsetof(SMU7_Discrete_PmFuses, TdcWaterfallCtl),
- (uint32_t *)&temp, SMC_RAM_END))
+ (uint32_t *)&smu_data->power_tune_table.TdcWaterfallCtl, SMC_RAM_END))
PP_ASSERT_WITH_CODE(false,
"Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
return -EINVAL);
@@ -1217,7 +1216,7 @@ static int ci_populate_single_memory_level(
}
memory_level->EnabledForThrottle = 1;
- memory_level->EnabledForActivity = 1;
+ memory_level->EnabledForActivity = 0;
memory_level->UpH = data->current_profile_setting.mclk_up_hyst;
memory_level->DownH = data->current_profile_setting.mclk_down_hyst;
memory_level->VoltageDownH = 0;
@@ -1322,6 +1321,14 @@ static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
return result;
}
+ if (data->mclk_dpm_key_disabled && dpm_table->mclk_table.count) {
+ /* Populate the table with the highest MCLK level when MCLK DPM is disabled */
+ for (i = 0; i < dpm_table->mclk_table.count - 1; i++) {
+ levels[i] = levels[dpm_table->mclk_table.count - 1];
+ levels[i].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH;
+ }
+ }
+
smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1;
dev_id = adev->pdev->device;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c
index 2b4faab37693..23c9f14bb208 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c
@@ -425,6 +425,7 @@ static int aldebaran_set_default_dpm_table(struct smu_context *smu)
dpm_table->dpm_levels[0].enabled = true;
dpm_table->dpm_levels[1].value = pptable->GfxclkFmax;
dpm_table->dpm_levels[1].enabled = true;
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c
index 32d5e2170d80..aa9deb7cd9da 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c
@@ -262,8 +262,9 @@ static void smu_v13_0_12_init_xgmi_data(struct smu_context *smu,
int ret;
if (smu_table->tables[SMU_TABLE_SMU_METRICS].version >= 0x13) {
- max_width = (uint8_t)static_metrics->MaxXgmiWidth;
- max_speed = (uint16_t)static_metrics->MaxXgmiBitrate;
+ max_width = (uint8_t)SMUQ10_ROUND(static_metrics->MaxXgmiWidth);
+ max_speed =
+ (uint16_t)SMUQ10_ROUND(static_metrics->MaxXgmiBitrate);
ret = 0;
} else {
MetricsTable_t *metrics = (MetricsTable_t *)smu_table->metrics_table;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
index 870bcc86fd79..c62b12d672d4 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
@@ -1122,6 +1122,7 @@ static int smu_v13_0_6_set_default_dpm_table(struct smu_context *smu)
/* gfxclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.gfx_table;
dpm_table->clk_type = SMU_GFXCLK;
+ dpm_table->flags = SMU_DPM_TABLE_FINE_GRAINED;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) {
/* In the case of gfxclk, only fine-grained dpm is honored.
* Get min/max values from FW.
diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_core.c b/drivers/gpu/drm/amd/ras/rascore/ras_core.c
index 3f56f26abd6d..1ad555eff592 100644
--- a/drivers/gpu/drm/amd/ras/rascore/ras_core.c
+++ b/drivers/gpu/drm/amd/ras/rascore/ras_core.c
@@ -62,14 +62,16 @@ int ras_core_convert_timestamp_to_time(struct ras_core_context *ras_core,
uint64_t timestamp, struct ras_time *tm)
{
int days_in_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
- uint64_t month = 0, day = 0, hour = 0, minute = 0, second = 0;
+ uint64_t month = 0, day = 0, hour = 0, minute = 0, second = 0, remainder;
uint32_t year = 0;
int seconds_per_day = 24 * 60 * 60;
int seconds_per_hour = 60 * 60;
int seconds_per_minute = 60;
int days, remaining_seconds;
- days = div64_u64_rem(timestamp, seconds_per_day, (uint64_t *)&remaining_seconds);
+ days = div64_u64_rem(timestamp, seconds_per_day, &remainder);
+ /* remainder will always be less than seconds_per_day. */
+ remaining_seconds = remainder;
/* utc_timestamp follows the Unix epoch */
year = 1970;
@@ -505,8 +507,11 @@ bool ras_core_is_enabled(struct ras_core_context *ras_core)
uint64_t ras_core_get_utc_second_timestamp(struct ras_core_context *ras_core)
{
- if (ras_core && ras_core->sys_fn &&
- ras_core->sys_fn->get_utc_second_timestamp)
+ if (!ras_core)
+ return 0;
+
+ if (ras_core->sys_fn &&
+ ras_core->sys_fn->get_utc_second_timestamp)
return ras_core->sys_fn->get_utc_second_timestamp(ras_core);
RAS_DEV_ERR(ras_core->dev, "Failed to get system timestamp!\n");
@@ -528,7 +533,9 @@ bool ras_core_ras_interrupt_detected(struct ras_core_context *ras_core)
ras_core->sys_fn->detect_ras_interrupt)
return ras_core->sys_fn->detect_ras_interrupt(ras_core);
- RAS_DEV_ERR(ras_core->dev, "Failed to detect ras interrupt!\n");
+ if (ras_core && ras_core->dev)
+ RAS_DEV_ERR(ras_core->dev, "Failed to detect ras interrupt!\n");
+
return false;
}
diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_umc.c b/drivers/gpu/drm/amd/ras/rascore/ras_umc.c
index 2abe8553e479..4fff0b3af75c 100644
--- a/drivers/gpu/drm/amd/ras/rascore/ras_umc.c
+++ b/drivers/gpu/drm/amd/ras/rascore/ras_umc.c
@@ -222,7 +222,7 @@ int ras_umc_log_pending_bad_bank(struct ras_core_context *ras_core)
mutex_lock(&ras_umc->pending_ecc_lock);
list_for_each_entry_safe(ecc_node,
tmp, &ras_umc->pending_ecc_list, node){
- if (ecc_node && !ras_umc_log_bad_bank(ras_core, &ecc_node->ecc)) {
+ if (!ras_umc_log_bad_bank(ras_core, &ecc_node->ecc)) {
list_del(&ecc_node->node);
kfree(ecc_node);
}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
index 6ee909f8d534..50e86f352838 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
@@ -4,6 +4,8 @@
* Author: James.Qian.Wang <james.qian.wang@arm.com>
*
*/
+#include <linux/overflow.h>
+
#include <drm/drm_device.h>
#include <drm/drm_fb_dma_helper.h>
#include <drm/drm_gem.h>
@@ -93,7 +95,9 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
kfb->afbc_size = kfb->offset_payload + n_blocks *
ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8,
AFBC_SUPERBLK_ALIGNMENT);
- min_size = kfb->afbc_size + fb->offsets[0];
+ if (check_add_overflow(kfb->afbc_size, fb->offsets[0], &min_size)) {
+ goto check_failed;
+ }
if (min_size > obj->size) {
DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n",
obj->size, min_size);
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c
index 9392c226ff5b..c7cd0234d168 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c
@@ -740,7 +740,7 @@ static void cdns_mhdp_fw_cb(const struct firmware *fw, void *context)
bridge_attached = mhdp->bridge_attached;
spin_unlock(&mhdp->start_lock);
if (bridge_attached) {
- if (mhdp->connector.dev)
+ if (mhdp->connector_ptr)
drm_kms_helper_hotplug_event(mhdp->bridge.dev);
else
drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp));
@@ -1636,6 +1636,7 @@ static int cdns_mhdp_connector_init(struct cdns_mhdp_device *mhdp)
return ret;
}
+ mhdp->connector_ptr = conn;
drm_connector_helper_add(conn, &cdns_mhdp_conn_helper_funcs);
ret = drm_display_info_set_bus_formats(&conn->display_info,
@@ -1915,17 +1916,25 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge,
struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge);
struct cdns_mhdp_bridge_state *mhdp_state;
struct drm_crtc_state *crtc_state;
- struct drm_connector *connector;
struct drm_connector_state *conn_state;
struct drm_bridge_state *new_state;
const struct drm_display_mode *mode;
u32 resp;
- int ret;
+ int ret = 0;
dev_dbg(mhdp->dev, "bridge enable\n");
mutex_lock(&mhdp->link_mutex);
+ mhdp->connector_ptr = drm_atomic_get_new_connector_for_encoder(state,
+ bridge->encoder);
+ if (WARN_ON(!mhdp->connector_ptr))
+ goto out;
+
+ conn_state = drm_atomic_get_new_connector_state(state, mhdp->connector_ptr);
+ if (WARN_ON(!conn_state))
+ goto out;
+
if (mhdp->plugged && !mhdp->link_up) {
ret = cdns_mhdp_link_up(mhdp);
if (ret < 0)
@@ -1945,15 +1954,6 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge,
cdns_mhdp_reg_write(mhdp, CDNS_DPTX_CAR,
resp | CDNS_VIF_CLK_EN | CDNS_VIF_CLK_RSTN);
- connector = drm_atomic_get_new_connector_for_encoder(state,
- bridge->encoder);
- if (WARN_ON(!connector))
- goto out;
-
- conn_state = drm_atomic_get_new_connector_state(state, connector);
- if (WARN_ON(!conn_state))
- goto out;
-
if (mhdp->hdcp_supported &&
mhdp->hw_state == MHDP_HW_READY &&
conn_state->content_protection ==
@@ -2030,6 +2030,7 @@ static void cdns_mhdp_atomic_disable(struct drm_bridge *bridge,
if (mhdp->info && mhdp->info->ops && mhdp->info->ops->disable)
mhdp->info->ops->disable(mhdp);
+ mhdp->connector_ptr = NULL;
mutex_unlock(&mhdp->link_mutex);
}
@@ -2122,6 +2123,10 @@ static int cdns_mhdp_atomic_check(struct drm_bridge *bridge,
{
struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge);
const struct drm_display_mode *mode = &crtc_state->adjusted_mode;
+ struct drm_connector_state *old_state, *new_state;
+ struct drm_atomic_state *state = crtc_state->state;
+ struct drm_connector *conn = mhdp->connector_ptr;
+ u64 old_cp, new_cp;
mutex_lock(&mhdp->link_mutex);
@@ -2141,6 +2146,25 @@ static int cdns_mhdp_atomic_check(struct drm_bridge *bridge,
if (mhdp->info)
bridge_state->input_bus_cfg.flags = *mhdp->info->input_bus_flags;
+ if (conn && mhdp->hdcp_supported) {
+ old_state = drm_atomic_get_old_connector_state(state, conn);
+ new_state = drm_atomic_get_new_connector_state(state, conn);
+ old_cp = old_state->content_protection;
+ new_cp = new_state->content_protection;
+
+ if (old_state->hdcp_content_type != new_state->hdcp_content_type &&
+ new_cp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
+ new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+ crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
+ crtc_state->mode_changed = true;
+ }
+
+ if (!new_state->crtc) {
+ if (old_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED)
+ new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+ }
+ }
+
mutex_unlock(&mhdp->link_mutex);
return 0;
}
@@ -2161,6 +2185,25 @@ static const struct drm_edid *cdns_mhdp_bridge_edid_read(struct drm_bridge *brid
return cdns_mhdp_edid_read(mhdp, connector);
}
+static enum drm_mode_status
+cdns_mhdp_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+ struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge);
+
+ mutex_lock(&mhdp->link_mutex);
+
+ if (!cdns_mhdp_bandwidth_ok(mhdp, mode, mhdp->link.num_lanes,
+ mhdp->link.rate)) {
+ mutex_unlock(&mhdp->link_mutex);
+ return MODE_CLOCK_HIGH;
+ }
+
+ mutex_unlock(&mhdp->link_mutex);
+ return MODE_OK;
+}
+
static const struct drm_bridge_funcs cdns_mhdp_bridge_funcs = {
.atomic_enable = cdns_mhdp_atomic_enable,
.atomic_disable = cdns_mhdp_atomic_disable,
@@ -2175,6 +2218,7 @@ static const struct drm_bridge_funcs cdns_mhdp_bridge_funcs = {
.edid_read = cdns_mhdp_bridge_edid_read,
.hpd_enable = cdns_mhdp_bridge_hpd_enable,
.hpd_disable = cdns_mhdp_bridge_hpd_disable,
+ .mode_valid = cdns_mhdp_bridge_mode_valid,
};
static bool cdns_mhdp_detect_hpd(struct cdns_mhdp_device *mhdp, bool *hpd_pulse)
@@ -2296,7 +2340,7 @@ static void cdns_mhdp_modeset_retry_fn(struct work_struct *work)
mhdp = container_of(work, typeof(*mhdp), modeset_retry_work);
- conn = &mhdp->connector;
+ conn = mhdp->connector_ptr;
/* Grab the locks before changing connector property */
mutex_lock(&conn->dev->mode_config.mutex);
@@ -2373,7 +2417,7 @@ static void cdns_mhdp_hpd_work(struct work_struct *work)
int ret;
ret = cdns_mhdp_update_link_status(mhdp);
- if (mhdp->connector.dev) {
+ if (mhdp->connector_ptr) {
if (ret < 0)
schedule_work(&mhdp->modeset_retry_work);
else
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h
index bad2fc0c7306..a76775c76895 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h
+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h
@@ -376,6 +376,7 @@ struct cdns_mhdp_device {
struct mutex link_mutex;
struct drm_connector connector;
+ struct drm_connector *connector_ptr;
struct drm_bridge bridge;
struct cdns_mhdp_link link;
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c
index 42248f179b69..21a7d2fb266e 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c
@@ -394,7 +394,7 @@ static int _cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp)
int ret;
dev_dbg(mhdp->dev, "[%s:%d] HDCP is being disabled...\n",
- mhdp->connector.name, mhdp->connector.base.id);
+ mhdp->connector_ptr->name, mhdp->connector_ptr->base.id);
ret = cdns_mhdp_hdcp_set_config(mhdp, 0, false);
@@ -436,6 +436,10 @@ static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp)
int ret = 0;
mutex_lock(&mhdp->hdcp.mutex);
+
+ if (!mhdp->connector_ptr)
+ goto out;
+
if (mhdp->hdcp.value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
goto out;
@@ -445,7 +449,7 @@ static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp)
dev_err(mhdp->dev,
"[%s:%d] HDCP link failed, retrying authentication\n",
- mhdp->connector.name, mhdp->connector.base.id);
+ mhdp->connector_ptr->name, mhdp->connector_ptr->base.id);
ret = _cdns_mhdp_hdcp_disable(mhdp);
if (ret) {
@@ -487,13 +491,19 @@ static void cdns_mhdp_hdcp_prop_work(struct work_struct *work)
struct cdns_mhdp_device *mhdp = container_of(hdcp,
struct cdns_mhdp_device,
hdcp);
- struct drm_device *dev = mhdp->connector.dev;
+ struct drm_device *dev = NULL;
struct drm_connector_state *state;
+ if (mhdp->connector_ptr)
+ dev = mhdp->connector_ptr->dev;
+
+ if (!dev)
+ return;
+
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
mutex_lock(&mhdp->hdcp.mutex);
if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
- state = mhdp->connector.state;
+ state = mhdp->connector_ptr->state;
state->content_protection = mhdp->hdcp.value;
}
mutex_unlock(&mhdp->hdcp.mutex);
diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
index 441fd32dc91c..d64e328bf542 100644
--- a/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
+++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
@@ -222,52 +222,58 @@ static const struct drm_bridge_funcs imx8qxp_pxl2dpi_bridge_funcs = {
imx8qxp_pxl2dpi_bridge_atomic_get_output_bus_fmts,
};
-static struct device_node *
+static int
imx8qxp_pxl2dpi_get_available_ep_from_port(struct imx8qxp_pxl2dpi *p2d,
- u32 port_id)
+ u32 port_id,
+ struct device_node **ep)
{
- struct device_node *port, *ep;
+ struct device_node *port;
+ int ret = 0;
int ep_cnt;
+ *ep = NULL;
+
port = of_graph_get_port_by_id(p2d->dev->of_node, port_id);
if (!port) {
DRM_DEV_ERROR(p2d->dev, "failed to get port@%u\n", port_id);
- return ERR_PTR(-ENODEV);
+ return -ENODEV;
}
ep_cnt = of_get_available_child_count(port);
if (ep_cnt == 0) {
DRM_DEV_ERROR(p2d->dev, "no available endpoints of port@%u\n",
port_id);
- ep = ERR_PTR(-ENODEV);
+ ret = -ENODEV;
goto out;
} else if (ep_cnt > 1) {
DRM_DEV_ERROR(p2d->dev,
"invalid available endpoints of port@%u\n",
port_id);
- ep = ERR_PTR(-EINVAL);
+ ret = -EINVAL;
goto out;
}
- ep = of_get_next_available_child(port, NULL);
- if (!ep) {
+ *ep = of_get_next_available_child(port, NULL);
+ if (!*ep) {
DRM_DEV_ERROR(p2d->dev,
"failed to get available endpoint of port@%u\n",
port_id);
- ep = ERR_PTR(-ENODEV);
+ ret = -ENODEV;
goto out;
}
out:
of_node_put(port);
- return ep;
+ return ret;
}
static int imx8qxp_pxl2dpi_find_next_bridge(struct imx8qxp_pxl2dpi *p2d)
{
- struct device_node *ep __free(device_node) =
- imx8qxp_pxl2dpi_get_available_ep_from_port(p2d, 1);
- if (IS_ERR(ep))
- return PTR_ERR(ep);
+ struct device_node *ep __free(device_node) = NULL;
+ int ret;
+
+ ret = imx8qxp_pxl2dpi_get_available_ep_from_port(p2d, 1, &ep);
+ if (ret)
+ return ret;
struct device_node *remote __free(device_node) = of_graph_get_remote_port_parent(ep);
if (!remote || !of_device_is_available(remote)) {
@@ -291,9 +297,9 @@ static int imx8qxp_pxl2dpi_set_pixel_link_sel(struct imx8qxp_pxl2dpi *p2d)
struct of_endpoint endpoint;
int ret;
- ep = imx8qxp_pxl2dpi_get_available_ep_from_port(p2d, 0);
- if (IS_ERR(ep))
- return PTR_ERR(ep);
+ ret = imx8qxp_pxl2dpi_get_available_ep_from_port(p2d, 0, &ep);
+ if (ret)
+ return ret;
ret = of_graph_parse_endpoint(ep, &endpoint);
if (ret) {
diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c
index c598b99673fc..e7db4e4ea700 100644
--- a/drivers/gpu/drm/drm_color_mgmt.c
+++ b/drivers/gpu/drm/drm_color_mgmt.c
@@ -831,7 +831,7 @@ static void fill_palette_332(struct drm_crtc *crtc, u16 r, u16 g, u16 b,
}
/**
- * drm_crtc_fill_palette_332 - Programs a default palette for R332-like formats
+ * drm_crtc_fill_palette_332 - Programs a default palette for RGB332-like formats
* @crtc: The displaying CRTC
* @set_palette: Callback for programming the hardware gamma LUT
*
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 05803169bed5..16bfbfb0af16 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1641,8 +1641,10 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper)
drm_client_modeset_probe(&fb_helper->client, width, height);
info = drm_fb_helper_alloc_info(fb_helper);
- if (IS_ERR(info))
+ if (IS_ERR(info)) {
+ mutex_unlock(&fb_helper->lock);
return PTR_ERR(info);
+ }
ret = drm_fb_helper_single_fb_probe(fb_helper);
if (ret < 0) {
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index ebf21b403b11..2b152e3103c3 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -1049,17 +1049,12 @@ int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data,
spin_unlock(&file_priv->table_lock);
- if (ret < 0)
- goto out_unlock;
-
if (obj->dma_buf) {
ret = drm_prime_add_buf_handle(&file_priv->prime, obj->dma_buf,
handle);
if (ret < 0) {
spin_lock(&file_priv->table_lock);
idr_remove(&file_priv->object_idr, handle);
- idrobj = idr_replace(&file_priv->object_idr, obj, handle);
- WARN_ON(idrobj != NULL);
spin_unlock(&file_priv->table_lock);
goto out_unlock;
}
@@ -1071,7 +1066,9 @@ int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data,
spin_lock(&file_priv->table_lock);
idr_remove(&file_priv->object_idr, args->handle);
+ idrobj = idr_replace(&file_priv->object_idr, obj, handle);
spin_unlock(&file_priv->table_lock);
+ WARN_ON(idrobj != NULL);
out_unlock:
mutex_unlock(&file_priv->prime.lock);
diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c
index 04bdc386c3fd..35dd07297dd0 100644
--- a/drivers/gpu/drm/drm_gpusvm.c
+++ b/drivers/gpu/drm/drm_gpusvm.c
@@ -819,7 +819,7 @@ enum drm_gpusvm_scan_result drm_gpusvm_scan_mm(struct drm_gpusvm_range *range,
if (!(pfns[i] & HMM_PFN_VALID)) {
state = DRM_GPUSVM_SCAN_UNPOPULATED;
- goto err_free;
+ break;
}
page = hmm_pfn_to_page(pfns[i]);
@@ -856,9 +856,9 @@ enum drm_gpusvm_scan_result drm_gpusvm_scan_mm(struct drm_gpusvm_range *range,
i += 1ul << drm_gpusvm_hmm_pfn_to_order(pfns[i], i, npages);
}
-err_free:
drm_gpusvm_notifier_unlock(range->gpusvm);
+err_free:
kvfree(pfns);
return state;
}
diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c
index 58d7e191fd56..403d21cbb3a2 100644
--- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c
+++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c
@@ -580,6 +580,7 @@ static int oaktrail_hdmi_get_modes(struct drm_connector *connector)
} else {
edid = (struct edid *)raw_edid;
/* FIXME ? edid = drm_get_edid(connector, i2c_adap); */
+ i2c_put_adapter(i2c_adap);
}
if (edid) {
diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c
index 884d324f0044..e194d0cce067 100644
--- a/drivers/gpu/drm/gma500/oaktrail_lvds.c
+++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c
@@ -293,7 +293,7 @@ void oaktrail_lvds_init(struct drm_device *dev,
{
struct gma_encoder *gma_encoder;
struct gma_connector *gma_connector;
- struct gma_i2c_chan *ddc_bus;
+ struct gma_i2c_chan *ddc_bus = NULL;
struct drm_connector *connector;
struct drm_encoder *encoder;
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
@@ -367,6 +367,8 @@ void oaktrail_lvds_init(struct drm_device *dev,
if (edid == NULL && dev_priv->lpc_gpio_base) {
ddc_bus = oaktrail_lvds_i2c_init(dev);
if (!IS_ERR(ddc_bus)) {
+ if (i2c_adap)
+ i2c_put_adapter(i2c_adap);
i2c_adap = &ddc_bus->base;
edid = drm_get_edid(connector, i2c_adap);
}
@@ -421,7 +423,10 @@ void oaktrail_lvds_init(struct drm_device *dev,
err_unlock:
mutex_unlock(&dev->mode_config.mutex);
- gma_i2c_destroy(to_gma_i2c_chan(connector->ddc));
+ if (!IS_ERR_OR_NULL(ddc_bus))
+ gma_i2c_destroy(ddc_bus);
+ else if (i2c_adap)
+ i2c_put_adapter(i2c_adap);
drm_encoder_cleanup(encoder);
err_connector_cleanup:
drm_connector_cleanup(connector);
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 696edf40b243..2906dc6e630e 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -2981,8 +2981,13 @@ static void intel_dp_compute_vsc_colorimetry(const struct intel_crtc_state *crtc
drm_WARN_ON(display->drm,
vsc->bpc == 6 && vsc->pixelformat != DP_PIXELFORMAT_RGB);
- /* all YCbCr are always limited range */
- vsc->dynamic_range = DP_DYNAMIC_RANGE_CTA;
+ /* All YCbCr formats are always limited range. */
+ if (vsc->pixelformat == DP_PIXELFORMAT_RGB)
+ vsc->dynamic_range = crtc_state->limited_color_range ?
+ DP_DYNAMIC_RANGE_CTA : DP_DYNAMIC_RANGE_VESA;
+ else
+ vsc->dynamic_range = DP_DYNAMIC_RANGE_CTA;
+
vsc->content_type = DP_CONTENT_TYPE_NOT_DEFINED;
}
diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c
index f5a6fae815d1..fa51f976ea72 100644
--- a/drivers/gpu/drm/i915/display/skl_watermark.c
+++ b/drivers/gpu/drm/i915/display/skl_watermark.c
@@ -3980,8 +3980,8 @@ void intel_wm_state_verify(struct intel_atomic_state *state,
}
/* DDB */
- hw_ddb_entry = &hw->ddb[PLANE_CURSOR];
- sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[PLANE_CURSOR];
+ hw_ddb_entry = &hw->ddb[plane->id];
+ sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[plane->id];
if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) {
drm_err(display->drm,
diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c
index 41b5036dc538..64ef68e6ac62 100644
--- a/drivers/gpu/drm/i915/gt/intel_reset.c
+++ b/drivers/gpu/drm/i915/gt/intel_reset.c
@@ -132,7 +132,8 @@ void __i915_request_reset(struct i915_request *rq, bool guilty)
rcu_read_lock(); /* protect the GEM context */
if (guilty) {
i915_request_set_error_once(rq, -EIO);
- __i915_request_skip(rq);
+ if (!i915_request_signaled(rq))
+ __i915_request_skip(rq);
banned = mark_guilty(rq);
} else {
i915_request_set_error_once(rq, -EAGAIN);
diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif.h
index 172886be4c82..5d590c4c2566 100644
--- a/drivers/gpu/drm/imagination/pvr_rogue_fwif.h
+++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif.h
@@ -1347,8 +1347,12 @@ struct rogue_fwif_fwccb_cmd_freelists_reconstruction_data {
struct rogue_fwif_fwccb_cmd_context_reset_data {
/* Context affected by the reset */
u32 server_common_context_id;
- /* Reason for reset */
- enum rogue_context_reset_reason reset_reason;
+ /*
+ * Reason for reset
+ * The valid values for reset_reason are the ones from
+ * enum rogue_context_reset_reason
+ */
+ u32 reset_reason;
/* Data Master affected by the reset */
u32 dm;
/* Job ref running at the time of reset */
diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h
index 6c09c15bf9bd..f95acd5a1f8e 100644
--- a/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h
+++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h
@@ -249,7 +249,11 @@ enum rogue_context_reset_reason {
};
struct rogue_context_reset_reason_data {
- enum rogue_context_reset_reason reset_reason;
+ /*
+ * The valid values for reset_reason are the ones from
+ * enum rogue_context_reset_reason
+ */
+ u32 reset_reason;
u32 reset_ext_job_ref;
};
diff --git a/drivers/gpu/drm/loongson/lsdc_drv.c b/drivers/gpu/drm/loongson/lsdc_drv.c
index abf5bf68eec2..4b97750897dc 100644
--- a/drivers/gpu/drm/loongson/lsdc_drv.c
+++ b/drivers/gpu/drm/loongson/lsdc_drv.c
@@ -292,7 +292,7 @@ static int lsdc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
vga_client_register(pdev, lsdc_vga_set_decode);
- drm_kms_helper_poll_init(ddev);
+ drmm_kms_helper_poll_init(ddev);
if (loongson_vblank) {
ret = drm_vblank_init(ddev, descp->num_of_crtc);
diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
index 8464d89e37f3..e6ab731f8e9a 100644
--- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
@@ -604,11 +604,9 @@ static int a4xx_pm_suspend(struct msm_gpu *gpu) {
return 0;
}
-static int a4xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
+static u64 a4xx_get_timestamp(struct msm_gpu *gpu)
{
- *value = gpu_read64(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_LO);
-
- return 0;
+ return gpu_read64(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_LO);
}
static u64 a4xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate)
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index ef9fd6171af7..e44302251de5 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -1435,11 +1435,9 @@ static int a5xx_pm_suspend(struct msm_gpu *gpu)
return 0;
}
-static int a5xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
+static u64 a5xx_get_timestamp(struct msm_gpu *gpu)
{
- *value = gpu_read64(gpu, REG_A5XX_RBBM_ALWAYSON_COUNTER_LO);
-
- return 0;
+ return gpu_read64(gpu, REG_A5XX_RBBM_ALWAYSON_COUNTER_LO);
}
struct a5xx_crashdumper {
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index 9662201cd2e9..1b44b9e21ad8 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -3,6 +3,7 @@
#include <linux/bitfield.h>
#include <linux/clk.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/interconnect.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
@@ -91,10 +92,10 @@ bool a6xx_gmu_sptprac_is_on(struct a6xx_gmu *gmu)
}
/* Check to see if the GX rail is still powered */
-bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu)
+bool a6xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu)
{
- struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu);
- struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
+ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+ struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
u32 val;
/* This can be called from gpu state code so make sure GMU is valid */
@@ -117,6 +118,40 @@ bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu)
A6XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_CLK_OFF));
}
+bool a7xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu)
+{
+ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+ struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
+ u32 val;
+
+ /* This can be called from gpu state code so make sure GMU is valid */
+ if (!gmu->initialized)
+ return false;
+
+ val = gmu_read(gmu, REG_A6XX_GMU_SPTPRAC_PWR_CLK_STATUS);
+
+ return !(val &
+ (A7XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_GDSC_POWER_OFF |
+ A7XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_CLK_OFF));
+}
+
+bool a8xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu)
+{
+ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+ struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
+ u32 val;
+
+ /* This can be called from gpu state code so make sure GMU is valid */
+ if (!gmu->initialized)
+ return false;
+
+ val = gmu_read(gmu, REG_A8XX_GMU_PWR_CLK_STATUS);
+
+ return !(val &
+ (A8XX_GMU_PWR_CLK_STATUS_GX_HM_GDSC_POWER_OFF |
+ A8XX_GMU_PWR_CLK_STATUS_GX_HM_CLK_OFF));
+}
+
void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp,
bool suspended)
{
@@ -240,7 +275,7 @@ static bool a6xx_gmu_check_idle_level(struct a6xx_gmu *gmu)
if (val == local) {
if (gmu->idle_level != GMU_IDLE_STATE_IFPC ||
- !a6xx_gmu_gx_is_on(gmu))
+ !adreno_gpu->funcs->gx_is_on(adreno_gpu))
return true;
}
@@ -1157,6 +1192,65 @@ static void a6xx_gmu_set_initial_bw(struct msm_gpu *gpu, struct a6xx_gmu *gmu)
dev_pm_opp_put(gpu_opp);
}
+static int a6xx_gmu_secure_init(struct a6xx_gpu *a6xx_gpu)
+{
+ struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
+ struct msm_gpu *gpu = &adreno_gpu->base;
+ struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
+ u32 fuse_val;
+ int ret;
+
+ if (test_bit(GMU_STATUS_SECURE_INIT, &gmu->status))
+ return 0;
+
+ if (adreno_is_a750(adreno_gpu) || adreno_is_a8xx(adreno_gpu)) {
+ /*
+ * Assume that if qcom scm isn't available, that whatever
+ * replacement allows writing the fuse register ourselves.
+ * Users of alternative firmware need to make sure this
+ * register is writeable or indicate that it's not somehow.
+ * Print a warning because if you mess this up you're about to
+ * crash horribly.
+ */
+ if (!qcom_scm_is_available()) {
+ dev_warn_once(gpu->dev->dev,
+ "SCM is not available, poking fuse register\n");
+ a6xx_llc_write(a6xx_gpu, REG_A7XX_CX_MISC_SW_FUSE_VALUE,
+ A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING |
+ A7XX_CX_MISC_SW_FUSE_VALUE_FASTBLEND |
+ A7XX_CX_MISC_SW_FUSE_VALUE_LPAC);
+ adreno_gpu->has_ray_tracing = true;
+ goto done;
+ }
+
+ ret = qcom_scm_gpu_init_regs(QCOM_SCM_GPU_ALWAYS_EN_REQ |
+ QCOM_SCM_GPU_TSENSE_EN_REQ);
+ if (ret) {
+ dev_warn_once(gpu->dev->dev,
+ "SCM call failed\n");
+ return ret;
+ }
+
+ /*
+ * On A7XX_GEN3 and newer, raytracing may be disabled by the
+ * firmware, find out whether that's the case. The scm call
+ * above sets the fuse register.
+ */
+ fuse_val = a6xx_llc_read(a6xx_gpu,
+ REG_A7XX_CX_MISC_SW_FUSE_VALUE);
+ adreno_gpu->has_ray_tracing =
+ !!(fuse_val & A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING);
+ } else if (adreno_is_a740(adreno_gpu)) {
+ /* Raytracing is always enabled on a740 */
+ adreno_gpu->has_ray_tracing = true;
+ }
+
+done:
+ set_bit(GMU_STATUS_SECURE_INIT, &gmu->status);
+ return 0;
+}
+
+
int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
{
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
@@ -1185,11 +1279,12 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
clk_set_rate(gmu->hub_clk, adreno_is_a740_family(adreno_gpu) ?
200000000 : 150000000);
ret = clk_bulk_prepare_enable(gmu->nr_clocks, gmu->clocks);
- if (ret) {
- pm_runtime_put(gmu->gxpd);
- pm_runtime_put(gmu->dev);
- return ret;
- }
+ if (ret)
+ goto rpm_put;
+
+ ret = a6xx_gmu_secure_init(a6xx_gpu);
+ if (ret)
+ goto disable_clk;
/* Read the slice info on A8x GPUs */
a8xx_gpu_get_slice_info(gpu);
@@ -1219,11 +1314,11 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
ret = a6xx_gmu_fw_start(gmu, status);
if (ret)
- goto out;
+ goto disable_irq;
ret = a6xx_hfi_start(gmu, status);
if (ret)
- goto out;
+ goto disable_irq;
/*
* Turn on the GMU firmware fault interrupt after we know the boot
@@ -1236,19 +1331,16 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
/* Set the GPU to the current freq */
a6xx_gmu_set_initial_freq(gpu, gmu);
- if (refcount_read(&gpu->sysprof_active) > 1) {
- ret = a6xx_gmu_set_oob(gmu, GMU_OOB_PERFCOUNTER_SET);
- if (!ret)
- set_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status);
- }
-out:
- /* On failure, shut down the GMU to leave it in a good state */
- if (ret) {
- disable_irq(gmu->gmu_irq);
- a6xx_rpmh_stop(gmu);
- pm_runtime_put(gmu->gxpd);
- pm_runtime_put(gmu->dev);
- }
+ return 0;
+
+disable_irq:
+ disable_irq(gmu->gmu_irq);
+ a6xx_rpmh_stop(gmu);
+disable_clk:
+ clk_bulk_disable_unprepare(gmu->nr_clocks, gmu->clocks);
+rpm_put:
+ pm_runtime_put(gmu->gxpd);
+ pm_runtime_put(gmu->dev);
return ret;
}
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
index 2af074c8e8cf..0cd8ae1b4f5c 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
@@ -10,6 +10,7 @@
#include <linux/notifier.h>
#include <linux/soc/qcom/qcom_aoss.h>
#include "msm_drv.h"
+#include "adreno_gpu.h"
#include "a6xx_hfi.h"
struct a6xx_gmu_bo {
@@ -129,6 +130,8 @@ struct a6xx_gmu {
#define GMU_STATUS_PDC_SLEEP 1
/* To track Perfcounter OOB set status */
#define GMU_STATUS_OOB_PERF_SET 2
+/* To track whether secure world init was done */
+#define GMU_STATUS_SECURE_INIT 3
unsigned long status;
};
@@ -231,7 +234,9 @@ void a6xx_hfi_stop(struct a6xx_gmu *gmu);
int a6xx_hfi_send_prep_slumber(struct a6xx_gmu *gmu);
int a6xx_hfi_set_freq(struct a6xx_gmu *gmu, u32 perf_index, u32 bw_index);
-bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu);
+bool a6xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu);
+bool a7xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu);
+bool a8xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu);
bool a6xx_gmu_sptprac_is_on(struct a6xx_gmu *gmu);
void a6xx_sptprac_disable(struct a6xx_gmu *gmu);
int a6xx_sptprac_enable(struct a6xx_gmu *gmu);
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index d6dfe6337bc3..0e8a48ca816d 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -10,14 +10,15 @@
#include <linux/bitfield.h>
#include <linux/devfreq.h>
-#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/pm_domain.h>
#include <linux/soc/qcom/llcc-qcom.h>
#define GPU_PAS_ID 13
-static u64 read_gmu_ao_counter(struct a6xx_gpu *a6xx_gpu)
+static u64 a6xx_gmu_get_timestamp(struct msm_gpu *gpu)
{
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
u64 count_hi, count_lo, temp;
do {
@@ -345,7 +346,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
* GPU registers so we need to add 0x1a800 to the register value on A630
* to get the right value from PM4.
*/
- get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_COUNTER,
+ get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_CONTEXT,
rbmemptr_stats(ring, index, alwayson_start));
/* Invalidate CCU depth and color */
@@ -386,7 +387,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
get_stats_counter(ring, REG_A6XX_RBBM_PERFCTR_CP(0),
rbmemptr_stats(ring, index, cpcycles_end));
- get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_COUNTER,
+ get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_CONTEXT,
rbmemptr_stats(ring, index, alwayson_end));
/* Write the fence to the scratch register */
@@ -404,7 +405,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
OUT_RING(ring, upper_32_bits(rbmemptr(ring, fence)));
OUT_RING(ring, submit->seqno);
- trace_msm_gpu_submit_flush(submit, read_gmu_ao_counter(a6xx_gpu));
+ trace_msm_gpu_submit_flush(submit, adreno_gpu->funcs->get_timestamp(gpu));
a6xx_flush(gpu, ring);
}
@@ -455,7 +456,7 @@ static void a7xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
struct msm_ringbuffer *ring = submit->ring;
- u32 rbbm_perfctr_cp0, cp_always_on_counter;
+ u32 rbbm_perfctr_cp0, cp_always_on_context;
unsigned int i, ibs = 0;
adreno_check_and_reenable_stall(adreno_gpu);
@@ -478,14 +479,14 @@ static void a7xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
if (adreno_is_a8xx(adreno_gpu)) {
rbbm_perfctr_cp0 = REG_A8XX_RBBM_PERFCTR_CP(0);
- cp_always_on_counter = REG_A8XX_CP_ALWAYS_ON_COUNTER;
+ cp_always_on_context = REG_A8XX_CP_ALWAYS_ON_CONTEXT;
} else {
rbbm_perfctr_cp0 = REG_A7XX_RBBM_PERFCTR_CP(0);
- cp_always_on_counter = REG_A6XX_CP_ALWAYS_ON_COUNTER;
+ cp_always_on_context = REG_A6XX_CP_ALWAYS_ON_CONTEXT;
}
get_stats_counter(ring, rbbm_perfctr_cp0, rbmemptr_stats(ring, index, cpcycles_start));
- get_stats_counter(ring, cp_always_on_counter, rbmemptr_stats(ring, index, alwayson_start));
+ get_stats_counter(ring, cp_always_on_context, rbmemptr_stats(ring, index, alwayson_start));
OUT_PKT7(ring, CP_THREAD_CONTROL, 1);
OUT_RING(ring, CP_SET_THREAD_BOTH);
@@ -533,7 +534,7 @@ static void a7xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
}
get_stats_counter(ring, rbbm_perfctr_cp0, rbmemptr_stats(ring, index, cpcycles_end));
- get_stats_counter(ring, cp_always_on_counter, rbmemptr_stats(ring, index, alwayson_end));
+ get_stats_counter(ring, cp_always_on_context, rbmemptr_stats(ring, index, alwayson_end));
/* Write the fence to the scratch register */
if (adreno_is_a8xx(adreno_gpu)) {
@@ -614,7 +615,7 @@ static void a7xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
}
- trace_msm_gpu_submit_flush(submit, read_gmu_ao_counter(a6xx_gpu));
+ trace_msm_gpu_submit_flush(submit, adreno_gpu->funcs->get_timestamp(gpu));
a6xx_flush(gpu, ring);
@@ -1603,6 +1604,12 @@ static int hw_init(struct msm_gpu *gpu)
a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_BOOT_SLUMBER);
}
+ if (!ret && (refcount_read(&gpu->sysprof_active) > 1)) {
+ ret = a6xx_gmu_set_oob(gmu, GMU_OOB_PERFCOUNTER_SET);
+ if (!ret)
+ set_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status);
+ }
+
return ret;
}
@@ -1635,7 +1642,7 @@ static void a6xx_recover(struct msm_gpu *gpu)
adreno_dump_info(gpu);
- if (a6xx_gmu_gx_is_on(&a6xx_gpu->gmu)) {
+ if (adreno_gpu->funcs->gx_is_on(adreno_gpu)) {
/* Sometimes crashstate capture is skipped, so SQE should be halted here again */
gpu_write(gpu, REG_A6XX_CP_SQE_CNTL, 3);
@@ -2152,56 +2159,6 @@ static void a6xx_llc_slices_init(struct platform_device *pdev,
a6xx_gpu->llc_mmio = ERR_PTR(-EINVAL);
}
-static int a7xx_cx_mem_init(struct a6xx_gpu *a6xx_gpu)
-{
- struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
- struct msm_gpu *gpu = &adreno_gpu->base;
- u32 fuse_val;
- int ret;
-
- if (adreno_is_a750(adreno_gpu) || adreno_is_a8xx(adreno_gpu)) {
- /*
- * Assume that if qcom scm isn't available, that whatever
- * replacement allows writing the fuse register ourselves.
- * Users of alternative firmware need to make sure this
- * register is writeable or indicate that it's not somehow.
- * Print a warning because if you mess this up you're about to
- * crash horribly.
- */
- if (!qcom_scm_is_available()) {
- dev_warn_once(gpu->dev->dev,
- "SCM is not available, poking fuse register\n");
- a6xx_llc_write(a6xx_gpu, REG_A7XX_CX_MISC_SW_FUSE_VALUE,
- A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING |
- A7XX_CX_MISC_SW_FUSE_VALUE_FASTBLEND |
- A7XX_CX_MISC_SW_FUSE_VALUE_LPAC);
- adreno_gpu->has_ray_tracing = true;
- return 0;
- }
-
- ret = qcom_scm_gpu_init_regs(QCOM_SCM_GPU_ALWAYS_EN_REQ |
- QCOM_SCM_GPU_TSENSE_EN_REQ);
- if (ret)
- return ret;
-
- /*
- * On A7XX_GEN3 and newer, raytracing may be disabled by the
- * firmware, find out whether that's the case. The scm call
- * above sets the fuse register.
- */
- fuse_val = a6xx_llc_read(a6xx_gpu,
- REG_A7XX_CX_MISC_SW_FUSE_VALUE);
- adreno_gpu->has_ray_tracing =
- !!(fuse_val & A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING);
- } else if (adreno_is_a740(adreno_gpu)) {
- /* Raytracing is always enabled on a740 */
- adreno_gpu->has_ray_tracing = true;
- }
-
- return 0;
-}
-
-
#define GBIF_CLIENT_HALT_MASK BIT(0)
#define GBIF_ARB_HALT_MASK BIT(1)
#define VBIF_XIN_HALT_CTRL0_MASK GENMASK(3, 0)
@@ -2414,20 +2371,9 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu)
return 0;
}
-static int a6xx_gmu_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
-{
- struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
- struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
-
- *value = read_gmu_ao_counter(a6xx_gpu);
-
- return 0;
-}
-
-static int a6xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
+static u64 a6xx_get_timestamp(struct msm_gpu *gpu)
{
- *value = gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER);
- return 0;
+ return gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER);
}
static struct msm_ringbuffer *a6xx_active_ring(struct msm_gpu *gpu)
@@ -2656,6 +2602,7 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
gpu = &adreno_gpu->base;
mutex_init(&a6xx_gpu->gmu.lock);
+ spin_lock_init(&a6xx_gpu->aperture_lock);
adreno_gpu->registers = NULL;
@@ -2708,14 +2655,6 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
return ERR_PTR(ret);
}
- if (adreno_is_a7xx(adreno_gpu) || adreno_is_a8xx(adreno_gpu)) {
- ret = a7xx_cx_mem_init(a6xx_gpu);
- if (ret) {
- a6xx_destroy(&(a6xx_gpu->base.base));
- return ERR_PTR(ret);
- }
- }
-
adreno_gpu->uche_trap_base = 0x1fffffffff000ull;
msm_mmu_set_fault_handler(to_msm_vm(gpu->vm)->mmu, gpu,
@@ -2765,6 +2704,7 @@ const struct adreno_gpu_funcs a6xx_gpu_funcs = {
.get_timestamp = a6xx_gmu_get_timestamp,
.bus_halt = a6xx_bus_clear_pending_transactions,
.mmu_fault_handler = a6xx_fault_handler,
+ .gx_is_on = a6xx_gmu_gx_is_on,
};
const struct adreno_gpu_funcs a6xx_gmuwrapper_funcs = {
@@ -2797,6 +2737,7 @@ const struct adreno_gpu_funcs a6xx_gmuwrapper_funcs = {
.get_timestamp = a6xx_get_timestamp,
.bus_halt = a6xx_bus_clear_pending_transactions,
.mmu_fault_handler = a6xx_fault_handler,
+ .gx_is_on = a6xx_gmu_gx_is_on,
};
const struct adreno_gpu_funcs a7xx_gpu_funcs = {
@@ -2831,6 +2772,7 @@ const struct adreno_gpu_funcs a7xx_gpu_funcs = {
.get_timestamp = a6xx_gmu_get_timestamp,
.bus_halt = a6xx_bus_clear_pending_transactions,
.mmu_fault_handler = a6xx_fault_handler,
+ .gx_is_on = a7xx_gmu_gx_is_on,
};
const struct adreno_gpu_funcs a8xx_gpu_funcs = {
@@ -2858,4 +2800,5 @@ const struct adreno_gpu_funcs a8xx_gpu_funcs = {
.get_timestamp = a8xx_gmu_get_timestamp,
.bus_halt = a8xx_bus_clear_pending_transactions,
.mmu_fault_handler = a8xx_fault_handler,
+ .gx_is_on = a8xx_gmu_gx_is_on,
};
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
index 4eaa04711246..a4434a6a56dd 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
@@ -320,7 +320,7 @@ int a6xx_zap_shader_init(struct msm_gpu *gpu);
void a8xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu, bool gx_off);
int a8xx_fault_handler(void *arg, unsigned long iova, int flags, void *data);
void a8xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring);
-int a8xx_gmu_get_timestamp(struct msm_gpu *gpu, uint64_t *value);
+u64 a8xx_gmu_get_timestamp(struct msm_gpu *gpu);
u64 a8xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate);
int a8xx_gpu_feature_probe(struct msm_gpu *gpu);
void a8xx_gpu_get_slice_info(struct msm_gpu *gpu);
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
index 2d56fe0a65b7..791623ddb67c 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
@@ -361,7 +361,7 @@ static void a6xx_get_debugbus_blocks(struct msm_gpu *gpu,
sizeof(*a6xx_state->debugbus));
if (a6xx_state->debugbus) {
- int i;
+ int i, j;
for (i = 0; i < ARRAY_SIZE(a6xx_debugbus_blocks); i++)
a6xx_get_debugbus_block(gpu,
@@ -369,8 +369,6 @@ static void a6xx_get_debugbus_blocks(struct msm_gpu *gpu,
&a6xx_debugbus_blocks[i],
&a6xx_state->debugbus[i]);
- a6xx_state->nr_debugbus = ARRAY_SIZE(a6xx_debugbus_blocks);
-
/*
* GBIF has same debugbus as of other GPU blocks, fall back to
* default path if GPU uses GBIF, also GBIF uses exactly same
@@ -381,17 +379,19 @@ static void a6xx_get_debugbus_blocks(struct msm_gpu *gpu,
&a6xx_gbif_debugbus_block,
&a6xx_state->debugbus[i]);
- a6xx_state->nr_debugbus += 1;
+ i++;
}
if (adreno_is_a650_family(to_adreno_gpu(gpu))) {
- for (i = 0; i < ARRAY_SIZE(a650_debugbus_blocks); i++)
+ for (j = 0; j < ARRAY_SIZE(a650_debugbus_blocks); i++, j++)
a6xx_get_debugbus_block(gpu,
a6xx_state,
- &a650_debugbus_blocks[i],
+ &a650_debugbus_blocks[j],
&a6xx_state->debugbus[i]);
}
+
+ a6xx_state->nr_debugbus = i;
}
}
@@ -1013,7 +1013,7 @@ static void a6xx_get_crashdumper_hlsq_registers(struct msm_gpu *gpu,
u64 out = dumper->iova + A6XX_CD_DATA_OFFSET;
int i, regcount = 0;
- in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, regs->val1);
+ in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, (regs->val1 & 0xff) << 8);
for (i = 0; i < regs->count; i += 2) {
u32 count = RANGE(regs->registers, i);
@@ -1251,7 +1251,7 @@ static void a6xx_get_gmu_registers(struct msm_gpu *gpu,
_a6xx_get_gmu_registers(gpu, a6xx_state, &a6xx_gpucc_reg,
&a6xx_state->gmu_registers[2], false);
- if (!a6xx_gmu_gx_is_on(&a6xx_gpu->gmu))
+ if (!adreno_gpu->funcs->gx_is_on(adreno_gpu))
return;
/* Set the fence to ALLOW mode so we can access the registers */
@@ -1607,7 +1607,7 @@ struct msm_gpu_state *a6xx_gpu_state_get(struct msm_gpu *gpu)
}
/* If GX isn't on the rest of the data isn't going to be accessible */
- if (!a6xx_gmu_gx_is_on(&a6xx_gpu->gmu))
+ if (!adreno_gpu->funcs->gx_is_on(adreno_gpu))
return &a6xx_state->base;
/* Halt SQE first */
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
index 53cfdf4e6c34..4f5dbf46132b 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
@@ -34,7 +34,7 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu,
struct a6xx_hfi_queue_header *header = queue->header;
u32 i, hdr, index = header->read_index;
- if (header->read_index == header->write_index) {
+ if (header->read_index == READ_ONCE(header->write_index)) {
header->rx_request = 1;
return 0;
}
@@ -62,7 +62,10 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu,
if (!gmu->legacy)
index = ALIGN(index, 4) % header->size;
- header->read_index = index;
+ /* Ensure all memory operations are complete before updating the read index */
+ dma_mb();
+
+ WRITE_ONCE(header->read_index, index);
return HFI_HEADER_SIZE(hdr);
}
@@ -74,7 +77,7 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu,
spin_lock(&queue->lock);
- space = CIRC_SPACE(header->write_index, header->read_index,
+ space = CIRC_SPACE(header->write_index, READ_ONCE(header->read_index),
header->size);
if (space < dwords) {
header->dropped++;
@@ -95,7 +98,10 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu,
queue->data[index] = 0xfafafafa;
}
- header->write_index = index;
+ /* Ensure all memory operations are complete before updating the write index */
+ dma_mb();
+
+ WRITE_ONCE(header->write_index, index);
spin_unlock(&queue->lock);
gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, 0x01);
diff --git a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
index b1887e0cf698..fafeac62aebf 100644
--- a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
@@ -711,6 +711,12 @@ static int hw_init(struct msm_gpu *gpu)
*/
a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_GPU_SET);
+ if (!ret && (refcount_read(&gpu->sysprof_active) > 1)) {
+ ret = a6xx_gmu_set_oob(gmu, GMU_OOB_PERFCOUNTER_SET);
+ if (!ret)
+ set_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status);
+ }
+
return ret;
}
@@ -1174,23 +1180,19 @@ void a8xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu, bool gx_
gpu_write(gpu, REG_A6XX_GBIF_HALT, 0x0);
}
-int a8xx_gmu_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
+u64 a8xx_gmu_get_timestamp(struct msm_gpu *gpu)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+ u64 count_hi, count_lo, temp;
- mutex_lock(&a6xx_gpu->gmu.lock);
-
- /* Force the GPU power on so we can read this register */
- a6xx_gmu_set_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET);
-
- *value = gpu_read64(gpu, REG_A8XX_CP_ALWAYS_ON_COUNTER);
-
- a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET);
-
- mutex_unlock(&a6xx_gpu->gmu.lock);
+ do {
+ count_hi = gmu_read(&a6xx_gpu->gmu, REG_A8XX_GMU_ALWAYS_ON_COUNTER_H);
+ count_lo = gmu_read(&a6xx_gpu->gmu, REG_A8XX_GMU_ALWAYS_ON_COUNTER_L);
+ temp = gmu_read(&a6xx_gpu->gmu, REG_A8XX_GMU_ALWAYS_ON_COUNTER_H);
+ } while (unlikely(count_hi != temp));
- return 0;
+ return (count_hi << 32) | count_lo;
}
u64 a8xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate)
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index d5fe6f6f0dec..785e99fb5bd5 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -391,13 +391,11 @@ int adreno_get_param(struct msm_gpu *gpu, struct msm_context *ctx,
return 0;
case MSM_PARAM_TIMESTAMP:
if (adreno_gpu->funcs->get_timestamp) {
- int ret;
-
pm_runtime_get_sync(&gpu->pdev->dev);
- ret = adreno_gpu->funcs->get_timestamp(gpu, value);
+ *value = adreno_gpu->funcs->get_timestamp(gpu);
pm_runtime_put_autosuspend(&gpu->pdev->dev);
- return ret;
+ return 0;
}
return -EINVAL;
case MSM_PARAM_PRIORITIES:
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index 1d0145f8b3ec..29097e6b4253 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -79,9 +79,10 @@ struct adreno_gpu;
struct adreno_gpu_funcs {
struct msm_gpu_funcs base;
struct msm_gpu *(*init)(struct drm_device *dev);
- int (*get_timestamp)(struct msm_gpu *gpu, uint64_t *value);
+ u64 (*get_timestamp)(struct msm_gpu *gpu);
void (*bus_halt)(struct adreno_gpu *adreno_gpu, bool gx_off);
int (*mmu_fault_handler)(void *arg, unsigned long iova, int flags, void *data);
+ bool (*gx_is_on)(struct adreno_gpu *adreno_gpu);
};
struct adreno_reglist {
diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h
index b44d02b48418..2162ff917b0f 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h
@@ -121,13 +121,6 @@ static const struct dpu_dspp_cfg msm8953_dspp[] = {
static const struct dpu_intf_cfg msm8953_intf[] = {
{
- .name = "intf_0", .id = INTF_0,
- .base = 0x6a000, .len = 0x268,
- .type = INTF_NONE,
- .prog_fetch_lines_worst_case = 14,
- .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 24),
- .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 25),
- }, {
.name = "intf_1", .id = INTF_1,
.base = 0x6a800, .len = 0x268,
.type = INTF_DSI,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 0f4921b1a892..cbb7caa194c1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -1410,7 +1410,8 @@ static struct msm_display_topology dpu_crtc_get_topology(
topology.num_lm = 2;
else if (topology.num_dsc == 2)
topology.num_lm = 2;
- else if (dpu_kms->catalog->caps->has_3d_merge)
+ else if (dpu_kms->catalog->caps->has_3d_merge &&
+ topology.num_dsc == 0)
topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1;
else
topology.num_lm = 1;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 61d7e65469b3..014b2c504eda 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -1461,8 +1461,6 @@ static int __maybe_unused dpu_runtime_suspend(struct device *dev)
struct msm_drm_private *priv = platform_get_drvdata(pdev);
struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms);
- /* Drop the performance state vote */
- dev_pm_opp_set_rate(dev, 0);
clk_bulk_disable_unprepare(dpu_kms->num_clocks, dpu_kms->clocks);
for (i = 0; i < dpu_kms->num_paths; i++)
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 476848bf8cd1..d2124d625485 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -210,6 +210,7 @@ static const struct of_device_id msm_dp_dt_match[] = {
{ .compatible = "qcom,x1e80100-dp", .data = &msm_dp_desc_x1e80100 },
{}
};
+MODULE_DEVICE_TABLE(of, msm_dp_dt_match);
static struct msm_dp_display_private *dev_get_dp_display_private(struct device *dev)
{
diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
index d8bb40ef820e..3c9f01ed6271 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.c
+++ b/drivers/gpu/drm/msm/dsi/dsi.c
@@ -198,6 +198,7 @@ static const struct of_device_id dt_match[] = {
{ .compatible = "qcom,dsi-ctrl-6g-qcm2290" },
{}
};
+MODULE_DEVICE_TABLE(of, dt_match);
static const struct dev_pm_ops dsi_pm_ops = {
SET_RUNTIME_PM_OPS(msm_dsi_runtime_suspend, msm_dsi_runtime_resume, NULL)
diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c
index bd3c51c350e7..da3fe6824495 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c
@@ -317,10 +317,10 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = {
&msm8996_dsi_cfg, &msm_dsi_6g_host_ops},
{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_2,
&msm8976_dsi_cfg, &msm_dsi_6g_host_ops},
+ {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_0_0,
+ &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops},
{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_1_0,
&sdm660_dsi_cfg, &msm_dsi_6g_v2_host_ops},
- {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_0,
- &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops},
{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_1,
&sdm845_dsi_cfg, &msm_dsi_6g_v2_host_ops},
{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_3_0,
diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h
index 5dc812028bd5..ccf06679608e 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h
+++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h
@@ -19,8 +19,8 @@
#define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001
#define MSM_DSI_6G_VER_MINOR_V1_4_1 0x10040001
#define MSM_DSI_6G_VER_MINOR_V1_4_2 0x10040002
+#define MSM_DSI_6G_VER_MINOR_V2_0_0 0x20000000
#define MSM_DSI_6G_VER_MINOR_V2_1_0 0x20010000
-#define MSM_DSI_6G_VER_MINOR_V2_2_0 0x20000000
#define MSM_DSI_6G_VER_MINOR_V2_2_1 0x20020001
#define MSM_DSI_6G_VER_MINOR_V2_3_0 0x20030000
#define MSM_DSI_6G_VER_MINOR_V2_3_1 0x20030001
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index db6da99375a1..1c0841a1c101 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -569,6 +569,7 @@ void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host)
* dsi_adjust_pclk_for_compression() - Adjust the pclk rate for compression case
* @mode: The selected mode for the DSI output
* @dsc: DRM DSC configuration for this DSI output
+ * @is_bonded_dsi: True if two DSI controllers are bonded
*
* Adjust the pclk rate by calculating a new hdisplay proportional to
* the compression ratio such that:
@@ -1033,8 +1034,9 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
/*
* DPU sends 3 bytes per pclk cycle to DSI. If widebus is
* enabled, MDP always sends out 48-bit compressed data per
- * pclk and on average, DSI consumes an amount of compressed
- * data equivalent to the uncompressed pixel depth per pclk.
+ * pclk and on average, for video mode, DSI consumes only an
+ * amount of compressed data equivalent to the uncompressed
+ * pixel depth per pclk.
*
* Calculate the number of pclks needed to transmit one line of
* the compressed data.
@@ -1046,10 +1048,14 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
* unused anyway.
*/
h_total -= hdisplay;
- if (wide_bus_enabled)
- bits_per_pclk = mipi_dsi_pixel_format_to_bpp(msm_host->format);
- else
+ if (wide_bus_enabled) {
+ if (msm_host->mode_flags & MIPI_DSI_MODE_VIDEO)
+ bits_per_pclk = dsc->bits_per_component * 3;
+ else
+ bits_per_pclk = 48;
+ } else {
bits_per_pclk = 24;
+ }
hdisplay = DIV_ROUND_UP(msm_dsc_get_bytes_per_line(msm_host->dsc) * 8, bits_per_pclk);
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
index 7937266de1d2..c59375aaae19 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
@@ -582,6 +582,7 @@ static const struct of_device_id dsi_phy_dt_match[] = {
#endif
{}
};
+MODULE_DEVICE_TABLE(of, dsi_phy_dt_match);
/*
* Currently, we only support one SoC for each PHY type. When we have multiple
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 5afac09c0d33..d5ef5089c9e9 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -441,6 +441,7 @@ static const struct of_device_id msm_hdmi_dt_match[] = {
{ .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8960_config },
{}
};
+MODULE_DEVICE_TABLE(of, msm_hdmi_dt_match);
static struct platform_driver msm_hdmi_driver = {
.probe = msm_hdmi_dev_probe,
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
index 667573f1db7c..f726555bb681 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
@@ -204,6 +204,7 @@ static const struct of_device_id msm_hdmi_phy_dt_match[] = {
.data = &msm_hdmi_phy_8998_cfg },
{}
};
+MODULE_DEVICE_TABLE(of, msm_hdmi_phy_dt_match);
static struct platform_driver msm_hdmi_phy_platform_driver = {
.probe = msm_hdmi_phy_probe,
diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c
index b3fdb83202ab..9b681e144c07 100644
--- a/drivers/gpu/drm/msm/msm_fb.c
+++ b/drivers/gpu/drm/msm/msm_fb.c
@@ -219,7 +219,12 @@ static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
+ mode_cmd->offsets[i];
if (bos[i]->size < min_size) {
- ret = -EINVAL;
+ ret = UERR(EINVAL, dev, "plane %d too small", i);
+ goto fail;
+ }
+
+ if (to_msm_bo(bos[i])->flags & MSM_BO_NO_SHARE) {
+ ret = UERR(EINVAL, dev, "Cannot map _NO_SHARE to kms vm");
goto fail;
}
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index b27abaa13926..2cb3ab04f125 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -507,8 +507,11 @@ void msm_gem_unpin_locked(struct drm_gem_object *obj)
*/
void msm_gem_unpin_active(struct drm_gem_object *obj)
{
+ struct msm_drm_private *priv = obj->dev->dev_private;
struct msm_gem_object *msm_obj = to_msm_bo(obj);
+ GEM_WARN_ON(!mutex_is_locked(&priv->lru.lock));
+
msm_obj->pin_count--;
GEM_WARN_ON(msm_obj->pin_count < 0);
update_lru_active(obj);
diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c
index 1039e3c0a47b..31fa51a44f86 100644
--- a/drivers/gpu/drm/msm/msm_gem_shrinker.c
+++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c
@@ -26,9 +26,8 @@ static bool can_swap(void)
static bool can_block(struct shrink_control *sc)
{
- if (!(sc->gfp_mask & __GFP_DIRECT_RECLAIM))
- return false;
- return current_is_kswapd() || (sc->gfp_mask & __GFP_RECLAIM);
+ return (sc->gfp_mask & __GFP_DIRECT_RECLAIM) ||
+ (current_is_kswapd() && (sc->gfp_mask & __GFP_KSWAPD_RECLAIM));
}
static unsigned long
diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c
index adf88cf8f41a..9e3632019bc9 100644
--- a/drivers/gpu/drm/msm/msm_gem_vma.c
+++ b/drivers/gpu/drm/msm/msm_gem_vma.c
@@ -696,6 +696,7 @@ static struct dma_fence *
msm_vma_job_run(struct drm_sched_job *_job)
{
struct msm_vm_bind_job *job = to_msm_vm_bind_job(_job);
+ struct msm_drm_private *priv = job->vm->drm->dev_private;
struct msm_gem_vm *vm = to_msm_vm(job->vm);
struct drm_gem_object *obj;
int ret = vm->unusable ? -EINVAL : 0;
@@ -738,12 +739,14 @@ msm_vma_job_run(struct drm_sched_job *_job)
if (ret)
msm_gem_vm_unusable(job->vm);
+ mutex_lock(&priv->lru.lock);
+
job_foreach_bo (obj, job) {
- msm_gem_lock(obj);
- msm_gem_unpin_locked(obj);
- msm_gem_unlock(obj);
+ msm_gem_unpin_active(obj);
}
+ mutex_unlock(&priv->lru.lock);
+
/* VM_BIND ops are synchronous, so no fence to wait on: */
return NULL;
}
@@ -1242,7 +1245,7 @@ vm_bind_job_lock_objects(struct msm_vm_bind_job *job, struct drm_exec *exec)
case MSM_VM_BIND_OP_UNMAP:
ret = drm_gpuvm_sm_unmap_exec_lock(job->vm, exec,
op->iova,
- op->obj_offset);
+ op->range);
break;
case MSM_VM_BIND_OP_MAP:
case MSM_VM_BIND_OP_MAP_NULL: {
diff --git a/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml b/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml
index c4e00b1263cd..33404eb18fd0 100644
--- a/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml
+++ b/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml
@@ -141,8 +141,10 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<reg32 offset="0x1f9f0" name="GMU_BOOT_KMD_LM_HANDSHAKE"/>
<reg32 offset="0x1f957" name="GMU_LLM_GLM_SLEEP_CTRL"/>
<reg32 offset="0x1f958" name="GMU_LLM_GLM_SLEEP_STATUS"/>
- <reg32 offset="0x1f888" name="GMU_ALWAYS_ON_COUNTER_L"/>
- <reg32 offset="0x1f889" name="GMU_ALWAYS_ON_COUNTER_H"/>
+ <reg32 offset="0x1f888" name="GMU_ALWAYS_ON_COUNTER_L" variants="A6XX-A7XX"/>
+ <reg32 offset="0x1f840" name="GMU_ALWAYS_ON_COUNTER_L" variants="A8XX-"/>
+ <reg32 offset="0x1f889" name="GMU_ALWAYS_ON_COUNTER_H" variants="A6XX-A7XX"/>
+ <reg32 offset="0x1f841" name="GMU_ALWAYS_ON_COUNTER_H" variants="A8XX-"/>
<reg32 offset="0x1f8c3" name="GMU_GMU_PWR_COL_KEEPALIVE" variants="A6XX-A7XX"/>
<reg32 offset="0x1f7e4" name="GMU_GMU_PWR_COL_KEEPALIVE" variants="A8XX-"/>
<reg32 offset="0x1f8c4" name="GMU_PWR_COL_PREEMPT_KEEPALIVE" variants="A6XX-A7XX"/>
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 307152ad7759..79264f7bbd0e 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -280,6 +280,7 @@ config DRM_PANEL_ILITEK_ILI9882T
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_DISPLAY_DSC_HELPER
help
Say Y if you want to enable support for panels based on the
Ilitek ILI9882t controller.
diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c
index 36abfa2e65e9..dd1eaba23ad3 100644
--- a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c
+++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c
@@ -201,6 +201,7 @@ static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt)
drm_panel_init(&sharp_nt->base, &sharp_nt->dsi->dev,
&sharp_nt_panel_funcs, DRM_MODE_CONNECTOR_DSI);
+ sharp_nt->base.prepare_prev_first = true;
ret = drm_panel_of_backlight(&sharp_nt->base);
if (ret)
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index 91ab280869ba..a242ae284db5 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -1295,7 +1295,7 @@ static const struct panel_desc auo_g190ean01 = {
.height = 301,
},
.delay = {
- .prepare = 50,
+ .prepare = 30,
.enable = 200,
.disable = 110,
.unprepare = 1000,
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index 711f5101aa04..074c0995ddc2 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -390,6 +390,8 @@ panfrost_ioctl_wait_bo(struct drm_device *dev, void *data,
true, timeout);
if (!ret)
ret = timeout ? -ETIMEDOUT : -EBUSY;
+ else if (ret > 0)
+ ret = 0;
drm_gem_object_put(gem_obj);
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index 40405a52a073..e989f75c09b7 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -491,6 +491,9 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) {
struct drm_plane_state *plane_state =
drm_atomic_get_plane_state(state, plane);
+ if (IS_ERR(plane_state))
+ return PTR_ERR(plane_state);
+
struct sun4i_layer_state *layer_state =
state_to_sun4i_layer_state(plane_state);
struct drm_framebuffer *fb = plane_state->fb;
@@ -878,7 +881,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
&sun4i_backend_regmap_config);
if (IS_ERR(backend->engine.regs)) {
dev_err(dev, "Couldn't create the backend regmap\n");
- return PTR_ERR(backend->engine.regs);
+ ret = PTR_ERR(backend->engine.regs);
+ goto err_disable_ram_clk;
}
list_add_tail(&backend->engine.list, &drv->engine_list);
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index ce9c155bfad7..02acc7cbdb97 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -321,7 +321,7 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
unsigned int phy_index;
int i;
- planes = devm_kcalloc(drm->dev, plane_cnt, sizeof(*planes), GFP_KERNEL);
+ planes = devm_kcalloc(drm->dev, plane_cnt + 1, sizeof(*planes), GFP_KERNEL);
if (!planes)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/gpu/drm/sysfb/ofdrm.c b/drivers/gpu/drm/sysfb/ofdrm.c
index d38ba70f4e0d..247cf13c80a0 100644
--- a/drivers/gpu/drm/sysfb/ofdrm.c
+++ b/drivers/gpu/drm/sysfb/ofdrm.c
@@ -350,6 +350,7 @@ static void ofdrm_pci_release(void *data)
struct pci_dev *pcidev = data;
pci_disable_device(pcidev);
+ pci_dev_put(pcidev);
}
static int ofdrm_device_init_pci(struct ofdrm_device *odev)
@@ -375,6 +376,7 @@ static int ofdrm_device_init_pci(struct ofdrm_device *odev)
if (ret) {
drm_err(dev, "pci_enable_device(%s) failed: %d\n",
dev_name(&pcidev->dev), ret);
+ pci_dev_put(pcidev);
return ret;
}
ret = devm_add_action_or_reset(&pdev->dev, ofdrm_pci_release, pcidev);
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 0765d69423d2..08d07ffbb167 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -740,7 +740,7 @@ static int ttm_bo_alloc_resource(struct ttm_buffer_object *bo,
may_evict = (force_space && place->mem_type != TTM_PL_SYSTEM);
ret = ttm_resource_alloc(bo, place, res, force_space ? &limit_pool : NULL);
if (ret) {
- if (ret != -ENOSPC && ret != -EAGAIN) {
+ if (ret != -ENOSPC) {
dmem_cgroup_pool_state_put(limit_pool);
return ret;
}
@@ -1178,17 +1178,13 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
bdev->funcs->swap_notify(bo);
if (ttm_tt_is_populated(tt)) {
- spin_lock(&bdev->lru_lock);
- ttm_resource_del_bulk_move(bo->resource, bo);
- spin_unlock(&bdev->lru_lock);
-
ret = ttm_tt_swapout(bdev, tt, swapout_walk->gfp_flags);
-
- spin_lock(&bdev->lru_lock);
- if (ret)
- ttm_resource_add_bulk_move(bo->resource, bo);
- ttm_resource_move_to_lru_tail(bo->resource);
- spin_unlock(&bdev->lru_lock);
+ if (!ret) {
+ spin_lock(&bdev->lru_lock);
+ ttm_resource_del_bulk_move_unevictable(bo->resource, bo);
+ ttm_resource_move_to_lru_tail(bo->resource);
+ spin_unlock(&bdev->lru_lock);
+ }
}
out:
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index f83b7d5ec6c6..3e3c201a0222 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -1112,19 +1112,14 @@ long ttm_bo_shrink(struct ttm_operation_ctx *ctx, struct ttm_buffer_object *bo,
if (lret < 0)
return lret;
- if (bo->bulk_move) {
- spin_lock(&bdev->lru_lock);
- ttm_resource_del_bulk_move(bo->resource, bo);
- spin_unlock(&bdev->lru_lock);
- }
-
lret = ttm_tt_backup(bdev, bo->ttm, (struct ttm_backup_flags)
{.purge = flags.purge,
.writeback = flags.writeback});
- if (lret <= 0 && bo->bulk_move) {
+ if (lret > 0) {
spin_lock(&bdev->lru_lock);
- ttm_resource_add_bulk_move(bo->resource, bo);
+ ttm_resource_del_bulk_move_unevictable(bo->resource, bo);
+ ttm_resource_move_to_lru_tail(bo->resource);
spin_unlock(&bdev->lru_lock);
}
diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c
index 192fca24f37e..bfd9c68fcd9c 100644
--- a/drivers/gpu/drm/ttm/ttm_resource.c
+++ b/drivers/gpu/drm/ttm/ttm_resource.c
@@ -292,6 +292,19 @@ void ttm_resource_del_bulk_move(struct ttm_resource *res,
ttm_lru_bulk_move_del(bo->bulk_move, res);
}
+/*
+ * Remove a resource from its bulk_move, bypassing the unevictable check.
+ * Use only when the resource is known to still be tracked in the range despite
+ * the BO having just become unevictable; asserts that this is the case.
+ */
+void ttm_resource_del_bulk_move_unevictable(struct ttm_resource *res,
+ struct ttm_buffer_object *bo)
+{
+ WARN_ON_ONCE(!ttm_resource_unevictable(res, bo));
+ if (bo->bulk_move)
+ ttm_lru_bulk_move_del(bo->bulk_move, res);
+}
+
/* Move a resource to the LRU or bulk tail */
void ttm_resource_move_to_lru_tail(struct ttm_resource *res)
{
@@ -385,8 +398,11 @@ int ttm_resource_alloc(struct ttm_buffer_object *bo,
if (man->cg) {
ret = dmem_cgroup_try_charge(man->cg, bo->base.size, &pool, ret_limit_pool);
- if (ret)
+ if (ret) {
+ if (ret == -EAGAIN)
+ ret = -ENOSPC;
return ret;
+ }
}
ret = man->func->alloc(man, bo, place, res_ptr);
diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c
index dd60acdf52c2..86e05fcf6cf6 100644
--- a/drivers/gpu/drm/v3d/v3d_drv.c
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
@@ -131,7 +131,7 @@ v3d_open(struct drm_device *dev, struct drm_file *file)
struct v3d_dev *v3d = to_v3d_dev(dev);
struct v3d_file_priv *v3d_priv;
struct drm_gpu_scheduler *sched;
- int i;
+ int i, ret;
v3d_priv = kzalloc_obj(*v3d_priv);
if (!v3d_priv)
@@ -141,9 +141,11 @@ v3d_open(struct drm_device *dev, struct drm_file *file)
for (i = 0; i < V3D_MAX_QUEUES; i++) {
sched = &v3d->queue[i].sched;
- drm_sched_entity_init(&v3d_priv->sched_entity[i],
- DRM_SCHED_PRIORITY_NORMAL, &sched,
- 1, NULL);
+ ret = drm_sched_entity_init(&v3d_priv->sched_entity[i],
+ DRM_SCHED_PRIORITY_NORMAL, &sched,
+ 1, NULL);
+ if (ret)
+ goto err_sched;
memset(&v3d_priv->stats[i], 0, sizeof(v3d_priv->stats[i]));
seqcount_init(&v3d_priv->stats[i].lock);
@@ -153,6 +155,12 @@ v3d_open(struct drm_device *dev, struct drm_file *file)
file->driver_priv = v3d_priv;
return 0;
+
+err_sched:
+ for (i--; i >= 0; i--)
+ drm_sched_entity_destroy(&v3d_priv->sched_entity[i]);
+ kfree(v3d_priv);
+ return ret;
}
static void
diff --git a/drivers/gpu/drm/virtio/virtgpu_prime.c b/drivers/gpu/drm/virtio/virtgpu_prime.c
index 8adcf5c15d45..05756ed4f1da 100644
--- a/drivers/gpu/drm/virtio/virtgpu_prime.c
+++ b/drivers/gpu/drm/virtio/virtgpu_prime.c
@@ -310,7 +310,7 @@ struct drm_gem_object *virtgpu_gem_prime_import(struct drm_device *dev,
}
}
- if (!vgdev->has_resource_blob || vgdev->has_virgl_3d)
+ if (!vgdev->has_resource_blob)
return drm_gem_prime_import(dev, buf);
bo = kzalloc_obj(*bo);
diff --git a/drivers/gpu/drm/xe/xe_dma_buf.c b/drivers/gpu/drm/xe/xe_dma_buf.c
index 19a8aba33085..f9e5fa3bd210 100644
--- a/drivers/gpu/drm/xe/xe_dma_buf.c
+++ b/drivers/gpu/drm/xe/xe_dma_buf.c
@@ -238,16 +238,8 @@ struct dma_buf *xe_gem_prime_export(struct drm_gem_object *obj, int flags)
return buf;
}
-/*
- * Takes ownership of @storage: on success it is transferred to the returned
- * drm_gem_object; on failure it is freed before returning the error.
- * This matches the contract of xe_bo_init_locked() which frees @storage on
- * its error paths, so callers need not (and must not) free @storage after
- * this call.
- */
static struct drm_gem_object *
-xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage,
- struct dma_buf *dma_buf)
+xe_dma_buf_create_obj(struct drm_device *dev, struct dma_buf *dma_buf)
{
struct dma_resv *resv = dma_buf->resv;
struct xe_device *xe = to_xe_device(dev);
@@ -258,10 +250,8 @@ xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage,
int ret = 0;
dummy_obj = drm_gpuvm_resv_object_alloc(&xe->drm);
- if (!dummy_obj) {
- xe_bo_free(storage);
+ if (!dummy_obj)
return ERR_PTR(-ENOMEM);
- }
dummy_obj->resv = resv;
xe_validation_guard(&ctx, &xe->val, &exec, (struct xe_val_flags) {}, ret) {
@@ -270,8 +260,7 @@ xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage,
if (ret)
break;
- /* xe_bo_init_locked() frees storage on error */
- bo = xe_bo_init_locked(xe, storage, NULL, resv, NULL, dma_buf->size,
+ bo = xe_bo_init_locked(xe, NULL, NULL, resv, NULL, dma_buf->size,
0, /* Will require 1way or 2way for vm_bind */
ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, &exec);
drm_exec_retry_on_contention(&exec);
@@ -322,7 +311,6 @@ struct drm_gem_object *xe_gem_prime_import(struct drm_device *dev,
const struct dma_buf_attach_ops *attach_ops;
struct dma_buf_attachment *attach;
struct drm_gem_object *obj;
- struct xe_bo *bo;
if (dma_buf->ops == &xe_dmabuf_ops) {
obj = dma_buf->priv;
@@ -338,13 +326,15 @@ struct drm_gem_object *xe_gem_prime_import(struct drm_device *dev,
}
/*
- * Don't publish the bo until we have a valid attachment, and a
- * valid attachment needs the bo address. So pre-create a bo before
- * creating the attachment and publish.
+ * This needs to happen before the attach, since it will create a new
+ * attachment for this, and add it to the list of attachments, at which
+ * point it is globally visible, and at any point the export side can
+ * call into on invalidate_mappings callback, which require a working
+ * object.
*/
- bo = xe_bo_alloc();
- if (IS_ERR(bo))
- return ERR_CAST(bo);
+ obj = xe_dma_buf_create_obj(dev, dma_buf);
+ if (IS_ERR(obj))
+ return obj;
attach_ops = &xe_dma_buf_attach_ops;
#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST)
@@ -352,29 +342,15 @@ struct drm_gem_object *xe_gem_prime_import(struct drm_device *dev,
attach_ops = test->attach_ops;
#endif
- attach = dma_buf_dynamic_attach(dma_buf, dev->dev, attach_ops, &bo->ttm.base);
+ attach = dma_buf_dynamic_attach(dma_buf, dev->dev, attach_ops, obj);
if (IS_ERR(attach)) {
- obj = ERR_CAST(attach);
- goto out_err;
+ xe_bo_put(gem_to_xe_bo(obj));
+ return ERR_CAST(attach);
}
- /*
- * xe_dma_buf_init_obj() takes ownership of bo on both success
- * and failure, so we must not touch bo after this call.
- */
- obj = xe_dma_buf_init_obj(dev, bo, dma_buf);
- if (IS_ERR(obj)) {
- dma_buf_detach(dma_buf, attach);
- return obj;
- }
get_dma_buf(dma_buf);
obj->import_attach = attach;
return obj;
-
-out_err:
- xe_bo_free(bo);
-
- return obj;
}
#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST)
diff --git a/drivers/gpu/drm/xe/xe_eu_stall.c b/drivers/gpu/drm/xe/xe_eu_stall.c
index 39723928a019..7da14854f688 100644
--- a/drivers/gpu/drm/xe/xe_eu_stall.c
+++ b/drivers/gpu/drm/xe/xe_eu_stall.c
@@ -869,14 +869,14 @@ static int xe_eu_stall_stream_close(struct inode *inode, struct file *file)
struct xe_eu_stall_data_stream *stream = file->private_data;
struct xe_gt *gt = stream->gt;
- drm_dev_put(>->tile->xe->drm);
-
mutex_lock(>->eu_stall->stream_lock);
xe_eu_stall_disable_locked(stream);
xe_eu_stall_data_buf_destroy(stream);
xe_eu_stall_stream_free(stream);
mutex_unlock(>->eu_stall->stream_lock);
+ drm_dev_put(>->tile->xe->drm);
+
return 0;
}
diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
index 8ecdf949f9e4..a49919da0eee 100644
--- a/drivers/gpu/drm/xe/xe_exec_queue.c
+++ b/drivers/gpu/drm/xe/xe_exec_queue.c
@@ -1227,7 +1227,7 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,
if (q->vm && q->hwe->hw_engine_group) {
err = xe_hw_engine_group_add_exec_queue(q->hwe->hw_engine_group, q);
if (err)
- goto put_exec_queue;
+ goto kill_exec_queue;
}
}
@@ -1236,12 +1236,15 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,
/* user id alloc must always be last in ioctl to prevent UAF */
err = xa_alloc(&xef->exec_queue.xa, &id, q, xa_limit_32b, GFP_KERNEL);
if (err)
- goto kill_exec_queue;
+ goto del_hw_engine_group;
args->exec_queue_id = id;
return 0;
+del_hw_engine_group:
+ if (q->vm && q->hwe && q->hwe->hw_engine_group)
+ xe_hw_engine_group_del_exec_queue(q->hwe->hw_engine_group, q);
kill_exec_queue:
xe_exec_queue_kill(q);
delete_queue_group:
@@ -1574,7 +1577,7 @@ void xe_exec_queue_tlb_inval_last_fence_put(struct xe_exec_queue *q,
void xe_exec_queue_tlb_inval_last_fence_put_unlocked(struct xe_exec_queue *q,
unsigned int type)
{
- xe_assert(q->vm->xe, type == XE_EXEC_QUEUE_TLB_INVAL_MEDIA_GT ||
+ xe_assert(gt_to_xe(q->gt), type == XE_EXEC_QUEUE_TLB_INVAL_MEDIA_GT ||
type == XE_EXEC_QUEUE_TLB_INVAL_PRIMARY_GT);
dma_fence_put(q->tlb_inval[type].last_fence);
diff --git a/drivers/gpu/drm/xe/xe_gsc.c b/drivers/gpu/drm/xe/xe_gsc.c
index e5c234f3d795..0d13e357fb43 100644
--- a/drivers/gpu/drm/xe/xe_gsc.c
+++ b/drivers/gpu/drm/xe/xe_gsc.c
@@ -166,7 +166,7 @@ static int query_compatibility_version(struct xe_gsc *gsc)
&rd_offset);
if (err) {
xe_gt_err(gt, "HuC: invalid GSC reply for version query (err=%d)\n", err);
- return err;
+ goto out_bo;
}
compat->major = version_query_rd(xe, &bo->vmap, rd_offset, proj_major);
diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c
index fc4f99d46763..82412c8dfd37 100644
--- a/drivers/gpu/drm/xe/xe_guc_submit.c
+++ b/drivers/gpu/drm/xe/xe_guc_submit.c
@@ -260,24 +260,12 @@ static void guc_submit_sw_fini(struct drm_device *drm, void *arg)
}
static void guc_submit_fini(void *arg)
-{
- struct xe_guc *guc = arg;
-
- /* Forcefully kill any remaining exec queues */
- xe_guc_ct_stop(&guc->ct);
- guc_submit_reset_prepare(guc);
- xe_guc_softreset(guc);
- xe_guc_submit_stop(guc);
- xe_uc_fw_sanitize(&guc->fw);
- xe_guc_submit_pause_abort(guc);
-}
-
-static void guc_submit_wedged_fini(void *arg)
{
struct xe_guc *guc = arg;
struct xe_exec_queue *q;
unsigned long index;
+ /* Drop any wedged queue refs */
mutex_lock(&guc->submission_state.lock);
xa_for_each(&guc->submission_state.exec_queue_lookup, index, q) {
if (exec_queue_wedged(q)) {
@@ -287,6 +275,14 @@ static void guc_submit_wedged_fini(void *arg)
}
}
mutex_unlock(&guc->submission_state.lock);
+
+ /* Forcefully kill any remaining exec queues */
+ xe_guc_ct_stop(&guc->ct);
+ guc_submit_reset_prepare(guc);
+ xe_guc_softreset(guc);
+ xe_guc_submit_stop(guc);
+ xe_uc_fw_sanitize(&guc->fw);
+ xe_guc_submit_pause_abort(guc);
}
static const struct xe_exec_queue_ops guc_exec_queue_ops;
@@ -1272,10 +1268,8 @@ static void disable_scheduling_deregister(struct xe_guc *guc,
void xe_guc_submit_wedge(struct xe_guc *guc)
{
struct xe_device *xe = guc_to_xe(guc);
- struct xe_gt *gt = guc_to_gt(guc);
struct xe_exec_queue *q;
unsigned long index;
- int err;
xe_gt_assert(guc_to_gt(guc), guc_to_xe(guc)->wedged.mode);
@@ -1286,15 +1280,7 @@ void xe_guc_submit_wedge(struct xe_guc *guc)
if (!guc->submission_state.initialized)
return;
- if (xe->wedged.mode == 2) {
- err = devm_add_action_or_reset(guc_to_xe(guc)->drm.dev,
- guc_submit_wedged_fini, guc);
- if (err) {
- xe_gt_err(gt, "Failed to register clean-up on wedged.mode=2; "
- "Although device is wedged.\n");
- return;
- }
-
+ if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) {
mutex_lock(&guc->submission_state.lock);
xa_for_each(&guc->submission_state.exec_queue_lookup, index, q)
if (xe_exec_queue_get_unless_zero(q))
diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c
index 7b70cc01fdb3..fc38cdcc3771 100644
--- a/drivers/gpu/drm/xe/xe_lrc.c
+++ b/drivers/gpu/drm/xe/xe_lrc.c
@@ -1202,7 +1202,7 @@ static ssize_t setup_invalidate_state_cache_wa(struct xe_lrc *lrc,
if (xe_gt_WARN_ON(lrc->gt, max_len < 3))
return -ENOSPC;
- *cmd++ = MI_LOAD_REGISTER_IMM | MI_LRI_NUM_REGS(1);
+ *cmd++ = MI_LOAD_REGISTER_IMM | MI_LRI_LRM_CS_MMIO | MI_LRI_NUM_REGS(1);
*cmd++ = CS_DEBUG_MODE2(0).addr;
*cmd++ = _MASKED_BIT_ENABLE(INSTRUCTION_STATE_CACHE_INVALIDATE);
diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c
index 1d36c09681aa..fc4b6f835d4b 100644
--- a/drivers/gpu/drm/xe/xe_reg_whitelist.c
+++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c
@@ -218,7 +218,7 @@ void xe_reg_whitelist_print_entry(struct drm_printer *p, unsigned int indent,
}
range_start = reg & REG_GENMASK(25, range_bit);
- range_end = range_start | REG_GENMASK(range_bit, 0);
+ range_end = range_start | REG_GENMASK(range_bit - 1, 0);
switch (val & RING_FORCE_TO_NONPRIV_ACCESS_MASK) {
case RING_FORCE_TO_NONPRIV_ACCESS_RW:
diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c
index d7e309ad9aba..9ddd21a21dce 100644
--- a/drivers/gpu/drm/xe/xe_wa.c
+++ b/drivers/gpu/drm/xe/xe_wa.c
@@ -708,6 +708,14 @@ static const struct xe_rtp_entry_sr lrc_was[] = {
XE_RTP_RULES(GRAPHICS_VERSION(1200)),
XE_RTP_ACTIONS(SET(COMMON_SLICE_CHICKEN4, DISABLE_TDC_LOAD_BALANCING_CALC))
},
+ { XE_RTP_NAME("14019877138"),
+ XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1255, 2004), ENGINE_CLASS(RENDER)),
+ XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FD_END_COLLECT))
+ },
+ { XE_RTP_NAME("14019386621"),
+ XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2004), ENGINE_CLASS(RENDER)),
+ XE_RTP_ACTIONS(SET(VF_SCRATCHPAD, XE2_VFG_TED_CREDIT_INTERFACE_DISABLE))
+ },
/* DG1 */
@@ -744,10 +752,6 @@ static const struct xe_rtp_entry_sr lrc_was[] = {
XE_RTP_RULES(PLATFORM(DG2)),
XE_RTP_ACTIONS(SET(CACHE_MODE_1, MSAA_OPTIMIZATION_REDUC_DISABLE))
},
- { XE_RTP_NAME("14019877138"),
- XE_RTP_RULES(PLATFORM(DG2)),
- XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FD_END_COLLECT))
- },
/* PVC */
@@ -765,21 +769,9 @@ static const struct xe_rtp_entry_sr lrc_was[] = {
XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1270, 1274)),
XE_RTP_ACTIONS(SET(CACHE_MODE_1, MSAA_OPTIMIZATION_REDUC_DISABLE))
},
- { XE_RTP_NAME("14019877138"),
- XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1270, 1274), ENGINE_CLASS(RENDER)),
- XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FD_END_COLLECT))
- },
/* Xe2_LPG */
- { XE_RTP_NAME("14019386621"),
- XE_RTP_RULES(GRAPHICS_VERSION(2004), ENGINE_CLASS(RENDER)),
- XE_RTP_ACTIONS(SET(VF_SCRATCHPAD, XE2_VFG_TED_CREDIT_INTERFACE_DISABLE))
- },
- { XE_RTP_NAME("14019877138"),
- XE_RTP_RULES(GRAPHICS_VERSION(2004), ENGINE_CLASS(RENDER)),
- XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FD_END_COLLECT))
- },
{ XE_RTP_NAME("14019988906"),
XE_RTP_RULES(GRAPHICS_VERSION(2004), ENGINE_CLASS(RENDER)),
XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FLSH_IGNORES_PSD))
@@ -813,14 +805,7 @@ static const struct xe_rtp_entry_sr lrc_was[] = {
},
/* Xe2_HPG */
- { XE_RTP_NAME("15010599737"),
- XE_RTP_RULES(GRAPHICS_VERSION(2001), ENGINE_CLASS(RENDER)),
- XE_RTP_ACTIONS(SET(CHICKEN_RASTER_1, DIS_SF_ROUND_NEAREST_EVEN))
- },
- { XE_RTP_NAME("14019386621"),
- XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2002), ENGINE_CLASS(RENDER)),
- XE_RTP_ACTIONS(SET(VF_SCRATCHPAD, XE2_VFG_TED_CREDIT_INTERFACE_DISABLE))
- },
+
{ XE_RTP_NAME("14020756599"),
XE_RTP_RULES(GRAPHICS_VERSION(2001), ENGINE_CLASS(RENDER)),
XE_RTP_ACTIONS(SET(WM_CHICKEN3, HIZ_PLANE_COMPRESSION_DIS))
@@ -829,10 +814,6 @@ static const struct xe_rtp_entry_sr lrc_was[] = {
XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2002), ENGINE_CLASS(RENDER)),
XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FLSH_IGNORES_PSD))
},
- { XE_RTP_NAME("14019877138"),
- XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2002), ENGINE_CLASS(RENDER)),
- XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FD_END_COLLECT))
- },
{ XE_RTP_NAME("14021490052"),
XE_RTP_RULES(GRAPHICS_VERSION(2001), ENGINE_CLASS(RENDER)),
XE_RTP_ACTIONS(SET(FF_MODE,
diff --git a/drivers/gpu/nova-core/bitfield.rs b/drivers/gpu/nova-core/bitfield.rs
index 16e143658c51..02efdcf78d89 100644
--- a/drivers/gpu/nova-core/bitfield.rs
+++ b/drivers/gpu/nova-core/bitfield.rs
@@ -314,12 +314,11 @@ fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result {
/// Returns a value for the bitfield where all fields are set to their default value.
impl ::core::default::Default for $name {
fn default() -> Self {
- #[allow(unused_mut)]
- let mut value = Self(Default::default());
+ let value = Self(Default::default());
::kernel::macros::paste!(
$(
- value.[<set_ $field>](Default::default());
+ let value = value.[<set_ $field>](Default::default());
)*
);
diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs
index 5a4cc047bcfc..e39885c0d5ca 100644
--- a/drivers/gpu/nova-core/driver.rs
+++ b/drivers/gpu/nova-core/driver.rs
@@ -70,7 +70,7 @@ impl pci::Driver for NovaCore {
fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> {
pin_init::pin_init_scope(move || {
- dev_dbg!(pdev.as_ref(), "Probe Nova Core GPU driver.\n");
+ dev_dbg!(pdev, "Probe Nova Core GPU driver.\n");
pdev.enable_device_mem()?;
pdev.set_master();
diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index 37bfee1d0949..808c17e981d1 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -2,12 +2,13 @@
//! Falcon microprocessor base support
-use core::ops::Deref;
-
use hal::FalconHal;
use kernel::{
- device,
+ device::{
+ self,
+ Device, //
+ },
dma::{
DmaAddress,
DmaMask, //
@@ -15,9 +16,7 @@
io::poll::read_poll_timeout,
prelude::*,
sync::aref::ARef,
- time::{
- Delta, //
- },
+ time::Delta,
};
use crate::{
@@ -327,9 +326,10 @@ pub(crate) trait FalconEngine:
const ID: Self;
}
-/// Represents a portion of the firmware to be loaded into a particular memory (e.g. IMEM or DMEM).
+/// Represents a portion of the firmware to be loaded into a particular memory (e.g. IMEM or DMEM)
+/// using DMA.
#[derive(Debug, Clone)]
-pub(crate) struct FalconLoadTarget {
+pub(crate) struct FalconDmaLoadTarget {
/// Offset from the start of the source object to copy from.
pub(crate) src_start: u32,
/// Offset from the start of the destination memory to copy into.
@@ -349,17 +349,20 @@ pub(crate) struct FalconBromParams {
pub(crate) ucode_id: u8,
}
-/// Trait for providing load parameters of falcon firmwares.
-pub(crate) trait FalconLoadParams {
+/// Trait implemented by falcon firmwares that can be loaded using DMA.
+pub(crate) trait FalconDmaLoadable {
+ /// Returns the firmware data as a slice of bytes.
+ fn as_slice(&self) -> &[u8];
+
/// Returns the load parameters for Secure `IMEM`.
- fn imem_sec_load_params(&self) -> FalconLoadTarget;
+ fn imem_sec_load_params(&self) -> FalconDmaLoadTarget;
/// Returns the load parameters for Non-Secure `IMEM`,
/// used only on Turing and GA100.
- fn imem_ns_load_params(&self) -> Option<FalconLoadTarget>;
+ fn imem_ns_load_params(&self) -> Option<FalconDmaLoadTarget>;
/// Returns the load parameters for `DMEM`.
- fn dmem_load_params(&self) -> FalconLoadTarget;
+ fn dmem_load_params(&self) -> FalconDmaLoadTarget;
/// Returns the parameters to write into the BROM registers.
fn brom_params(&self) -> FalconBromParams;
@@ -370,9 +373,8 @@ pub(crate) trait FalconLoadParams {
/// Trait for a falcon firmware.
///
-/// A falcon firmware can be loaded on a given engine, and is presented in the form of a DMA
-/// object.
-pub(crate) trait FalconFirmware: FalconLoadParams + Deref<Target = DmaObject> {
+/// A falcon firmware can be loaded on a given engine.
+pub(crate) trait FalconFirmware: FalconDmaLoadable {
/// Engine on which this firmware is to be loaded.
type Target: FalconEngine;
}
@@ -415,12 +417,12 @@ pub(crate) fn reset(&self, bar: &Bar0) -> Result {
/// `target_mem`.
///
/// `sec` is set if the loaded firmware is expected to run in secure mode.
- fn dma_wr<F: FalconFirmware<Target = E>>(
+ fn dma_wr(
&self,
bar: &Bar0,
- fw: &F,
+ dma_obj: &DmaObject,
target_mem: FalconMem,
- load_offsets: FalconLoadTarget,
+ load_offsets: FalconDmaLoadTarget,
) -> Result {
const DMA_LEN: u32 = 256;
@@ -430,11 +432,11 @@ fn dma_wr<F: FalconFirmware<Target = E>>(
// For DMEM we can fold the start offset into the DMA handle.
let (src_start, dma_start) = match target_mem {
FalconMem::ImemSecure | FalconMem::ImemNonSecure => {
- (load_offsets.src_start, fw.dma_handle())
+ (load_offsets.src_start, dma_obj.dma_handle())
}
FalconMem::Dmem => (
0,
- fw.dma_handle_with_offset(load_offsets.src_start.into_safe_cast())?,
+ dma_obj.dma_handle_with_offset(load_offsets.src_start.into_safe_cast())?,
),
};
if dma_start % DmaAddress::from(DMA_LEN) > 0 {
@@ -466,7 +468,7 @@ fn dma_wr<F: FalconFirmware<Target = E>>(
dev_err!(self.dev, "DMA transfer length overflow\n");
return Err(EOVERFLOW);
}
- Some(upper_bound) if usize::from_safe_cast(upper_bound) > fw.size() => {
+ Some(upper_bound) if usize::from_safe_cast(upper_bound) > dma_obj.size() => {
dev_err!(self.dev, "DMA transfer goes beyond range of DMA object\n");
return Err(EINVAL);
}
@@ -515,7 +517,12 @@ fn dma_wr<F: FalconFirmware<Target = E>>(
}
/// Perform a DMA load into `IMEM` and `DMEM` of `fw`, and prepare the falcon to run it.
- fn dma_load<F: FalconFirmware<Target = E>>(&self, bar: &Bar0, fw: &F) -> Result {
+ fn dma_load<F: FalconFirmware<Target = E>>(
+ &self,
+ dev: &Device<device::Bound>,
+ bar: &Bar0,
+ fw: &F,
+ ) -> Result {
// The Non-Secure section only exists on firmware used by Turing and GA100, and
// those platforms do not use DMA.
if fw.imem_ns_load_params().is_some() {
@@ -523,14 +530,22 @@ fn dma_load<F: FalconFirmware<Target = E>>(&self, bar: &Bar0, fw: &F) -> Result
return Err(EINVAL);
}
+ // Create DMA object with firmware content as the source of the DMA engine.
+ let dma_obj = DmaObject::from_data(dev, fw.as_slice())?;
+
self.dma_reset(bar);
regs::NV_PFALCON_FBIF_TRANSCFG::update(bar, &E::ID, 0, |v| {
v.set_target(FalconFbifTarget::CoherentSysmem)
.set_mem_type(FalconFbifMemType::Physical)
});
- self.dma_wr(bar, fw, FalconMem::ImemSecure, fw.imem_sec_load_params())?;
- self.dma_wr(bar, fw, FalconMem::Dmem, fw.dmem_load_params())?;
+ self.dma_wr(
+ bar,
+ &dma_obj,
+ FalconMem::ImemSecure,
+ fw.imem_sec_load_params(),
+ )?;
+ self.dma_wr(bar, &dma_obj, FalconMem::Dmem, fw.dmem_load_params())?;
self.hal.program_brom(self, bar, &fw.brom_params())?;
@@ -641,9 +656,14 @@ pub(crate) fn is_riscv_active(&self, bar: &Bar0) -> bool {
}
// Load a firmware image into Falcon memory
- pub(crate) fn load<F: FalconFirmware<Target = E>>(&self, bar: &Bar0, fw: &F) -> Result {
+ pub(crate) fn load<F: FalconFirmware<Target = E>>(
+ &self,
+ dev: &Device<device::Bound>,
+ bar: &Bar0,
+ fw: &F,
+ ) -> Result {
match self.hal.load_method() {
- LoadMethod::Dma => self.dma_load(bar, fw),
+ LoadMethod::Dma => self.dma_load(dev, bar, fw),
LoadMethod::Pio => Err(ENOTSUPP),
}
}
diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs
index 68779540aa28..6a5811864865 100644
--- a/drivers/gpu/nova-core/firmware.rs
+++ b/drivers/gpu/nova-core/firmware.rs
@@ -15,10 +15,9 @@
};
use crate::{
- dma::DmaObject,
falcon::{
- FalconFirmware,
- FalconLoadTarget, //
+ FalconDmaLoadTarget,
+ FalconFirmware, //
},
gpu,
num::{
@@ -64,7 +63,8 @@ pub(crate) struct FalconUCodeDescV2 {
pub(crate) interface_offset: u32,
/// Base address at which to load the code segment into 'IMEM'.
pub(crate) imem_phys_base: u32,
- /// Size in bytes of the code to copy into 'IMEM'.
+ /// Size in bytes of the code to copy into 'IMEM' (includes both secure and non-secure
+ /// segments).
pub(crate) imem_load_size: u32,
/// Virtual 'IMEM' address (i.e. 'tag') at which the code should start.
pub(crate) imem_virt_base: u32,
@@ -171,9 +171,9 @@ fn size(&self) -> usize {
((hdr & HDR_SIZE_MASK) >> HDR_SIZE_SHIFT).into_safe_cast()
}
- fn imem_sec_load_params(&self) -> FalconLoadTarget;
- fn imem_ns_load_params(&self) -> Option<FalconLoadTarget>;
- fn dmem_load_params(&self) -> FalconLoadTarget;
+ fn imem_sec_load_params(&self) -> FalconDmaLoadTarget;
+ fn imem_ns_load_params(&self) -> Option<FalconDmaLoadTarget>;
+ fn dmem_load_params(&self) -> FalconDmaLoadTarget;
}
impl FalconUCodeDescriptor for FalconUCodeDescV2 {
@@ -205,24 +205,31 @@ fn signature_versions(&self) -> u16 {
0
}
- fn imem_sec_load_params(&self) -> FalconLoadTarget {
- FalconLoadTarget {
- src_start: 0,
- dst_start: self.imem_sec_base,
+ fn imem_sec_load_params(&self) -> FalconDmaLoadTarget {
+ // `imem_sec_base` is the *virtual* start address of the secure IMEM segment, so subtract
+ // `imem_virt_base` to get its physical offset.
+ let imem_sec_start = self.imem_sec_base.saturating_sub(self.imem_virt_base);
+
+ FalconDmaLoadTarget {
+ src_start: imem_sec_start,
+ dst_start: self.imem_phys_base.saturating_add(imem_sec_start),
len: self.imem_sec_size,
}
}
- fn imem_ns_load_params(&self) -> Option<FalconLoadTarget> {
- Some(FalconLoadTarget {
+ fn imem_ns_load_params(&self) -> Option<FalconDmaLoadTarget> {
+ Some(FalconDmaLoadTarget {
+ // Non-secure code always starts at offset 0.
src_start: 0,
dst_start: self.imem_phys_base,
- len: self.imem_load_size.checked_sub(self.imem_sec_size)?,
+ // `imem_load_size` includes the size of the secure segment, so subtract it to
+ // get the correct amount of data to copy.
+ len: self.imem_load_size.saturating_sub(self.imem_sec_size),
})
}
- fn dmem_load_params(&self) -> FalconLoadTarget {
- FalconLoadTarget {
+ fn dmem_load_params(&self) -> FalconDmaLoadTarget {
+ FalconDmaLoadTarget {
src_start: self.dmem_offset,
dst_start: self.dmem_phys_base,
len: self.dmem_load_size,
@@ -259,21 +266,21 @@ fn signature_versions(&self) -> u16 {
self.signature_versions
}
- fn imem_sec_load_params(&self) -> FalconLoadTarget {
- FalconLoadTarget {
+ fn imem_sec_load_params(&self) -> FalconDmaLoadTarget {
+ FalconDmaLoadTarget {
src_start: 0,
dst_start: self.imem_phys_base,
len: self.imem_load_size,
}
}
- fn imem_ns_load_params(&self) -> Option<FalconLoadTarget> {
+ fn imem_ns_load_params(&self) -> Option<FalconDmaLoadTarget> {
// Not used on V3 platforms
None
}
- fn dmem_load_params(&self) -> FalconLoadTarget {
- FalconLoadTarget {
+ fn dmem_load_params(&self) -> FalconDmaLoadTarget {
+ FalconDmaLoadTarget {
src_start: self.imem_load_size,
dst_start: self.dmem_phys_base,
len: self.dmem_load_size,
@@ -292,7 +299,7 @@ impl SignedState for Unsigned {}
struct Signed;
impl SignedState for Signed {}
-/// A [`DmaObject`] containing a specific microcode ready to be loaded into a falcon.
+/// Microcode to be loaded into a specific falcon.
///
/// This is module-local and meant for sub-modules to use internally.
///
@@ -300,34 +307,35 @@ impl SignedState for Signed {}
/// before it can be loaded (with an exception for development hardware). The
/// [`Self::patch_signature`] and [`Self::no_patch_signature`] methods are used to transition the
/// firmware to its [`Signed`] state.
-struct FirmwareDmaObject<F: FalconFirmware, S: SignedState>(DmaObject, PhantomData<(F, S)>);
+// TODO: Consider replacing this with a coherent memory object once `CoherentAllocation` supports
+// temporary CPU-exclusive access to the object without unsafe methods.
+struct FirmwareObject<F: FalconFirmware, S: SignedState>(KVVec<u8>, PhantomData<(F, S)>);
/// Trait for signatures to be patched directly into a given firmware.
///
/// This is module-local and meant for sub-modules to use internally.
trait FirmwareSignature<F: FalconFirmware>: AsRef<[u8]> {}
-impl<F: FalconFirmware> FirmwareDmaObject<F, Unsigned> {
- /// Patches the firmware at offset `sig_base_img` with `signature`.
+impl<F: FalconFirmware> FirmwareObject<F, Unsigned> {
+ /// Patches the firmware at offset `signature_start` with `signature`.
fn patch_signature<S: FirmwareSignature<F>>(
mut self,
signature: &S,
- sig_base_img: usize,
- ) -> Result<FirmwareDmaObject<F, Signed>> {
+ signature_start: usize,
+ ) -> Result<FirmwareObject<F, Signed>> {
let signature_bytes = signature.as_ref();
- if sig_base_img + signature_bytes.len() > self.0.size() {
- return Err(EINVAL);
- }
-
- // SAFETY: We are the only user of this object, so there cannot be any race.
- let dst = unsafe { self.0.start_ptr_mut().add(sig_base_img) };
+ let signature_end = signature_start
+ .checked_add(signature_bytes.len())
+ .ok_or(EOVERFLOW)?;
+ let dst = self
+ .0
+ .get_mut(signature_start..signature_end)
+ .ok_or(EINVAL)?;
- // SAFETY: `signature` and `dst` are valid, properly aligned, and do not overlap.
- unsafe {
- core::ptr::copy_nonoverlapping(signature_bytes.as_ptr(), dst, signature_bytes.len())
- };
+ // PANIC: `dst` and `signature_bytes` have the same length.
+ dst.copy_from_slice(signature_bytes);
- Ok(FirmwareDmaObject(self.0, PhantomData))
+ Ok(FirmwareObject(self.0, PhantomData))
}
/// Mark the firmware as signed without patching it.
@@ -335,8 +343,8 @@ fn patch_signature<S: FirmwareSignature<F>>(
/// This method is used to explicitly confirm that we do not need to sign the firmware, while
/// allowing us to continue as if it was. This is typically only needed for development
/// hardware.
- fn no_patch_signature(self) -> FirmwareDmaObject<F, Signed> {
- FirmwareDmaObject(self.0, PhantomData)
+ fn no_patch_signature(self) -> FirmwareObject<F, Signed> {
+ FirmwareObject(self.0, PhantomData)
}
}
diff --git a/drivers/gpu/nova-core/firmware/booter.rs b/drivers/gpu/nova-core/firmware/booter.rs
index 86556cee8e67..1a6b2a7e1790 100644
--- a/drivers/gpu/nova-core/firmware/booter.rs
+++ b/drivers/gpu/nova-core/firmware/booter.rs
@@ -4,10 +4,7 @@
//! running on [`Sec2`], that is used on Turing/Ampere to load the GSP firmware into the GSP falcon
//! (and optionally unload it through a separate firmware image).
-use core::{
- marker::PhantomData,
- ops::Deref, //
-};
+use core::marker::PhantomData;
use kernel::{
device,
@@ -16,19 +13,18 @@
};
use crate::{
- dma::DmaObject,
driver::Bar0,
falcon::{
sec2::Sec2,
Falcon,
FalconBromParams,
- FalconFirmware,
- FalconLoadParams,
- FalconLoadTarget, //
+ FalconDmaLoadTarget,
+ FalconDmaLoadable,
+ FalconFirmware, //
},
firmware::{
BinFirmware,
- FirmwareDmaObject,
+ FirmwareObject,
FirmwareSignature,
Signed,
Unsigned, //
@@ -252,21 +248,24 @@ impl<'a> FirmwareSignature<BooterFirmware> for BooterSignature<'a> {}
/// The `Booter` loader firmware, responsible for loading the GSP.
pub(crate) struct BooterFirmware {
// Load parameters for Secure `IMEM` falcon memory.
- imem_sec_load_target: FalconLoadTarget,
+ imem_sec_load_target: FalconDmaLoadTarget,
// Load parameters for Non-Secure `IMEM` falcon memory,
// used only on Turing and GA100
- imem_ns_load_target: Option<FalconLoadTarget>,
+ imem_ns_load_target: Option<FalconDmaLoadTarget>,
// Load parameters for `DMEM` falcon memory.
- dmem_load_target: FalconLoadTarget,
+ dmem_load_target: FalconDmaLoadTarget,
// BROM falcon parameters.
brom_params: FalconBromParams,
// Device-mapped firmware image.
- ucode: FirmwareDmaObject<Self, Signed>,
+ ucode: FirmwareObject<Self, Signed>,
}
-impl FirmwareDmaObject<BooterFirmware, Unsigned> {
- fn new_booter(dev: &device::Device<device::Bound>, data: &[u8]) -> Result<Self> {
- DmaObject::from_data(dev, data).map(|ucode| Self(ucode, PhantomData))
+impl FirmwareObject<BooterFirmware, Unsigned> {
+ fn new_booter(data: &[u8]) -> Result<Self> {
+ let mut ucode = KVVec::new();
+ ucode.extend_from_slice(data, GFP_KERNEL)?;
+
+ Ok(Self(ucode, PhantomData))
}
}
@@ -320,7 +319,7 @@ pub(crate) fn new(
let ucode = bin_fw
.data()
.ok_or(EINVAL)
- .and_then(|data| FirmwareDmaObject::<Self, _>::new_booter(dev, data))?;
+ .and_then(FirmwareObject::<Self, _>::new_booter)?;
let ucode_signed = {
let mut signatures = hs_fw.signatures_iter()?.peekable();
@@ -363,7 +362,7 @@ pub(crate) fn new(
let (imem_sec_dst_start, imem_ns_load_target) = if chipset <= Chipset::GA100 {
(
app0.offset,
- Some(FalconLoadTarget {
+ Some(FalconDmaLoadTarget {
src_start: 0,
dst_start: load_hdr.os_code_offset,
len: load_hdr.os_code_size,
@@ -374,13 +373,13 @@ pub(crate) fn new(
};
Ok(Self {
- imem_sec_load_target: FalconLoadTarget {
+ imem_sec_load_target: FalconDmaLoadTarget {
src_start: app0.offset,
dst_start: imem_sec_dst_start,
len: app0.len,
},
imem_ns_load_target,
- dmem_load_target: FalconLoadTarget {
+ dmem_load_target: FalconDmaLoadTarget {
src_start: load_hdr.os_data_offset,
dst_start: 0,
len: load_hdr.os_data_size,
@@ -391,16 +390,20 @@ pub(crate) fn new(
}
}
-impl FalconLoadParams for BooterFirmware {
- fn imem_sec_load_params(&self) -> FalconLoadTarget {
+impl FalconDmaLoadable for BooterFirmware {
+ fn as_slice(&self) -> &[u8] {
+ self.ucode.0.as_slice()
+ }
+
+ fn imem_sec_load_params(&self) -> FalconDmaLoadTarget {
self.imem_sec_load_target.clone()
}
- fn imem_ns_load_params(&self) -> Option<FalconLoadTarget> {
+ fn imem_ns_load_params(&self) -> Option<FalconDmaLoadTarget> {
self.imem_ns_load_target.clone()
}
- fn dmem_load_params(&self) -> FalconLoadTarget {
+ fn dmem_load_params(&self) -> FalconDmaLoadTarget {
self.dmem_load_target.clone()
}
@@ -417,14 +420,6 @@ fn boot_addr(&self) -> u32 {
}
}
-impl Deref for BooterFirmware {
- type Target = DmaObject;
-
- fn deref(&self) -> &Self::Target {
- &self.ucode.0
- }
-}
-
impl FalconFirmware for BooterFirmware {
type Target = Sec2;
}
diff --git a/drivers/gpu/nova-core/firmware/fwsec.rs b/drivers/gpu/nova-core/firmware/fwsec.rs
index bfb7b06b13d1..7ac5cfeb594d 100644
--- a/drivers/gpu/nova-core/firmware/fwsec.rs
+++ b/drivers/gpu/nova-core/firmware/fwsec.rs
@@ -10,10 +10,7 @@
//! - The command to be run, as this firmware can perform several tasks ;
//! - The ucode signature, so the GSP falcon can run FWSEC in HS mode.
-use core::{
- marker::PhantomData,
- ops::Deref, //
-};
+use core::marker::PhantomData;
use kernel::{
device::{
@@ -28,27 +25,23 @@
};
use crate::{
- dma::DmaObject,
driver::Bar0,
falcon::{
gsp::Gsp,
Falcon,
FalconBromParams,
- FalconFirmware,
- FalconLoadParams,
- FalconLoadTarget, //
+ FalconDmaLoadTarget,
+ FalconDmaLoadable,
+ FalconFirmware, //
},
firmware::{
FalconUCodeDesc,
- FirmwareDmaObject,
+ FirmwareObject,
FirmwareSignature,
Signed,
Unsigned, //
},
- num::{
- FromSafeCast,
- IntoSafeCast, //
- },
+ num::FromSafeCast,
vbios::Vbios,
};
@@ -177,61 +170,30 @@ fn as_ref(&self) -> &[u8] {
impl FirmwareSignature<FwsecFirmware> for Bcrt30Rsa3kSignature {}
-/// Reinterpret the area starting from `offset` in `fw` as an instance of `T` (which must implement
-/// [`FromBytes`]) and return a reference to it.
-///
-/// # Safety
-///
-/// * Callers must ensure that the device does not read/write to/from memory while the returned
-/// reference is live.
-/// * Callers must ensure that this call does not race with a write to the same region while
-/// the returned reference is live.
-unsafe fn transmute<T: Sized + FromBytes>(fw: &DmaObject, offset: usize) -> Result<&T> {
- // SAFETY: The safety requirements of the function guarantee the device won't read
- // or write to memory while the reference is alive and that this call won't race
- // with writes to the same memory region.
- T::from_bytes(unsafe { fw.as_slice(offset, size_of::<T>())? }).ok_or(EINVAL)
-}
-
-/// Reinterpret the area starting from `offset` in `fw` as a mutable instance of `T` (which must
-/// implement [`FromBytes`]) and return a reference to it.
-///
-/// # Safety
-///
-/// * Callers must ensure that the device does not read/write to/from memory while the returned
-/// slice is live.
-/// * Callers must ensure that this call does not race with a read or write to the same region
-/// while the returned slice is live.
-unsafe fn transmute_mut<T: Sized + FromBytes + AsBytes>(
- fw: &mut DmaObject,
- offset: usize,
-) -> Result<&mut T> {
- // SAFETY: The safety requirements of the function guarantee the device won't read
- // or write to memory while the reference is alive and that this call won't race
- // with writes or reads to the same memory region.
- T::from_bytes_mut(unsafe { fw.as_slice_mut(offset, size_of::<T>())? }).ok_or(EINVAL)
-}
-
/// The FWSEC microcode, extracted from the BIOS and to be run on the GSP falcon.
///
/// It is responsible for e.g. carving out the WPR2 region as the first step of the GSP bootflow.
pub(crate) struct FwsecFirmware {
/// Descriptor of the firmware.
desc: FalconUCodeDesc,
- /// GPU-accessible DMA object containing the firmware.
- ucode: FirmwareDmaObject<Self, Signed>,
+ /// Object containing the firmware binary.
+ ucode: FirmwareObject<Self, Signed>,
}
-impl FalconLoadParams for FwsecFirmware {
- fn imem_sec_load_params(&self) -> FalconLoadTarget {
+impl FalconDmaLoadable for FwsecFirmware {
+ fn as_slice(&self) -> &[u8] {
+ self.ucode.0.as_slice()
+ }
+
+ fn imem_sec_load_params(&self) -> FalconDmaLoadTarget {
self.desc.imem_sec_load_params()
}
- fn imem_ns_load_params(&self) -> Option<FalconLoadTarget> {
+ fn imem_ns_load_params(&self) -> Option<FalconDmaLoadTarget> {
self.desc.imem_ns_load_params()
}
- fn dmem_load_params(&self) -> FalconLoadTarget {
+ fn dmem_load_params(&self) -> FalconDmaLoadTarget {
self.desc.dmem_load_params()
}
@@ -248,27 +210,27 @@ fn boot_addr(&self) -> u32 {
}
}
-impl Deref for FwsecFirmware {
- type Target = DmaObject;
-
- fn deref(&self) -> &Self::Target {
- &self.ucode.0
- }
-}
-
impl FalconFirmware for FwsecFirmware {
type Target = Gsp;
}
-impl FirmwareDmaObject<FwsecFirmware, Unsigned> {
- fn new_fwsec(dev: &Device<device::Bound>, bios: &Vbios, cmd: FwsecCommand) -> Result<Self> {
+impl FirmwareObject<FwsecFirmware, Unsigned> {
+ fn new_fwsec(bios: &Vbios, cmd: FwsecCommand) -> Result<Self> {
let desc = bios.fwsec_image().header()?;
- let ucode = bios.fwsec_image().ucode(&desc)?;
- let mut dma_object = DmaObject::from_data(dev, ucode)?;
+ let mut ucode = KVVec::new();
+ ucode.extend_from_slice(bios.fwsec_image().ucode(&desc)?, GFP_KERNEL)?;
+
+ let hdr_offset = desc
+ .imem_load_size()
+ .checked_add(desc.interface_offset())
+ .map(usize::from_safe_cast)
+ .ok_or(EINVAL)?;
- let hdr_offset = usize::from_safe_cast(desc.imem_load_size() + desc.interface_offset());
- // SAFETY: we have exclusive access to `dma_object`.
- let hdr: &FalconAppifHdrV1 = unsafe { transmute(&dma_object, hdr_offset) }?;
+ let hdr = ucode
+ .get(hdr_offset..)
+ .and_then(FalconAppifHdrV1::from_bytes_prefix)
+ .ok_or(EINVAL)?
+ .0;
if hdr.version != 1 {
return Err(EINVAL);
@@ -276,26 +238,34 @@ fn new_fwsec(dev: &Device<device::Bound>, bios: &Vbios, cmd: FwsecCommand) -> Re
// Find the DMEM mapper section in the firmware.
for i in 0..usize::from(hdr.entry_count) {
- // SAFETY: we have exclusive access to `dma_object`.
- let app: &FalconAppifV1 = unsafe {
- transmute(
- &dma_object,
- hdr_offset + usize::from(hdr.header_size) + i * usize::from(hdr.entry_size),
- )
- }?;
+ // CALC: hdr_offset + header_size + i * entry_size.
+ let entry_offset = hdr_offset
+ .checked_add(usize::from(hdr.header_size))
+ .and_then(|o| o.checked_add(i.checked_mul(usize::from(hdr.entry_size))?))
+ .ok_or(EINVAL)?;
+
+ let app = ucode
+ .get(entry_offset..)
+ .and_then(FalconAppifV1::from_bytes_prefix)
+ .ok_or(EINVAL)?
+ .0;
if app.id != NVFW_FALCON_APPIF_ID_DMEMMAPPER {
continue;
}
let dmem_base = app.dmem_base;
- // SAFETY: we have exclusive access to `dma_object`.
- let dmem_mapper: &mut FalconAppifDmemmapperV3 = unsafe {
- transmute_mut(
- &mut dma_object,
- (desc.imem_load_size() + dmem_base).into_safe_cast(),
- )
- }?;
+ let dmem_mapper_offset = desc
+ .imem_load_size()
+ .checked_add(dmem_base)
+ .map(usize::from_safe_cast)
+ .ok_or(EINVAL)?;
+
+ let dmem_mapper = ucode
+ .get_mut(dmem_mapper_offset..)
+ .and_then(FalconAppifDmemmapperV3::from_bytes_mut_prefix)
+ .ok_or(EINVAL)?
+ .0;
dmem_mapper.init_cmd = match cmd {
FwsecCommand::Frts { .. } => NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS,
@@ -303,13 +273,17 @@ fn new_fwsec(dev: &Device<device::Bound>, bios: &Vbios, cmd: FwsecCommand) -> Re
};
let cmd_in_buffer_offset = dmem_mapper.cmd_in_buffer_offset;
- // SAFETY: we have exclusive access to `dma_object`.
- let frts_cmd: &mut FrtsCmd = unsafe {
- transmute_mut(
- &mut dma_object,
- (desc.imem_load_size() + cmd_in_buffer_offset).into_safe_cast(),
- )
- }?;
+ let frts_cmd_offset = desc
+ .imem_load_size()
+ .checked_add(cmd_in_buffer_offset)
+ .map(usize::from_safe_cast)
+ .ok_or(EINVAL)?;
+
+ let frts_cmd = ucode
+ .get_mut(frts_cmd_offset..)
+ .and_then(FrtsCmd::from_bytes_mut_prefix)
+ .ok_or(EINVAL)?
+ .0;
frts_cmd.read_vbios = ReadVbios {
ver: 1,
@@ -333,7 +307,7 @@ fn new_fwsec(dev: &Device<device::Bound>, bios: &Vbios, cmd: FwsecCommand) -> Re
}
// Return early as we found and patched the DMEMMAPPER region.
- return Ok(Self(dma_object, PhantomData));
+ return Ok(Self(ucode, PhantomData));
}
Err(ENOTSUPP)
@@ -350,13 +324,16 @@ pub(crate) fn new(
bios: &Vbios,
cmd: FwsecCommand,
) -> Result<Self> {
- let ucode_dma = FirmwareDmaObject::<Self, _>::new_fwsec(dev, bios, cmd)?;
+ let ucode_dma = FirmwareObject::<Self, _>::new_fwsec(bios, cmd)?;
// Patch signature if needed.
let desc = bios.fwsec_image().header()?;
let ucode_signed = if desc.signature_count() != 0 {
- let sig_base_img =
- usize::from_safe_cast(desc.imem_load_size() + desc.pkc_data_offset());
+ let sig_base_img = desc
+ .imem_load_size()
+ .checked_add(desc.pkc_data_offset())
+ .map(usize::from_safe_cast)
+ .ok_or(EINVAL)?;
let desc_sig_versions = u32::from(desc.signature_versions());
let reg_fuse_version =
falcon.signature_reg_fuse_version(bar, desc.engine_id_mask(), desc.ucode_id())?;
@@ -419,7 +396,7 @@ pub(crate) fn run(
.reset(bar)
.inspect_err(|e| dev_err!(dev, "Failed to reset GSP falcon: {:?}\n", e))?;
falcon
- .load(bar, self)
+ .load(dev, bar, self)
.inspect_err(|e| dev_err!(dev, "Failed to load FWSEC firmware: {:?}\n", e))?;
let (mbox0, _) = falcon
.boot(bar, Some(0), None)
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 9b042ef1a308..60c85fffaeaf 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -262,13 +262,13 @@ pub(crate) fn new<'a>(
) -> impl PinInit<Self, Error> + 'a {
try_pin_init!(Self {
spec: Spec::new(pdev.as_ref(), bar).inspect(|spec| {
- dev_info!(pdev.as_ref(),"NVIDIA ({})\n", spec);
+ dev_info!(pdev,"NVIDIA ({})\n", spec);
})?,
// We must wait for GFW_BOOT completion before doing any significant setup on the GPU.
_: {
gfw::wait_gfw_boot_completion(bar)
- .inspect_err(|_| dev_err!(pdev.as_ref(), "GFW boot did not complete\n"))?;
+ .inspect_err(|_| dev_err!(pdev, "GFW boot did not complete\n"))?;
},
sysmem_flush: SysmemFlush::register(pdev.as_ref(), bar, spec.chipset)?,
diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs
index 94833f7996e8..99e7a0b7e310 100644
--- a/drivers/gpu/nova-core/gsp/boot.rs
+++ b/drivers/gpu/nova-core/gsp/boot.rs
@@ -170,39 +170,25 @@ pub(crate) fn boot(
Some(libos_handle as u32),
Some((libos_handle >> 32) as u32),
)?;
- dev_dbg!(
- pdev.as_ref(),
- "GSP MBOX0: {:#x}, MBOX1: {:#x}\n",
- mbox0,
- mbox1
- );
+ dev_dbg!(pdev, "GSP MBOX0: {:#x}, MBOX1: {:#x}\n", mbox0, mbox1);
dev_dbg!(
- pdev.as_ref(),
+ pdev,
"Using SEC2 to load and run the booter_load firmware...\n"
);
sec2_falcon.reset(bar)?;
- sec2_falcon.load(bar, &booter_loader)?;
+ sec2_falcon.load(dev, bar, &booter_loader)?;
let wpr_handle = wpr_meta.dma_handle();
let (mbox0, mbox1) = sec2_falcon.boot(
bar,
Some(wpr_handle as u32),
Some((wpr_handle >> 32) as u32),
)?;
- dev_dbg!(
- pdev.as_ref(),
- "SEC2 MBOX0: {:#x}, MBOX1{:#x}\n",
- mbox0,
- mbox1
- );
+ dev_dbg!(pdev, "SEC2 MBOX0: {:#x}, MBOX1: {:#x}\n", mbox0, mbox1);
if mbox0 != 0 {
- dev_err!(
- pdev.as_ref(),
- "Booter-load failed with error {:#x}\n",
- mbox0
- );
+ dev_err!(pdev, "Booter-load failed with error {:#x}\n", mbox0);
return Err(ENODEV);
}
@@ -216,11 +202,7 @@ pub(crate) fn boot(
Delta::from_secs(5),
)?;
- dev_dbg!(
- pdev.as_ref(),
- "RISC-V active? {}\n",
- gsp_falcon.is_riscv_active(bar),
- );
+ dev_dbg!(pdev, "RISC-V active? {}\n", gsp_falcon.is_riscv_active(bar),);
// Create and run the GSP sequencer.
let seq_params = GspSequencerParams {
@@ -239,8 +221,8 @@ pub(crate) fn boot(
// Obtain and display basic GPU information.
let info = commands::get_gsp_info(&mut self.cmdq, bar)?;
match info.gpu_name() {
- Ok(name) => dev_info!(pdev.as_ref(), "GPU name: {}\n", name),
- Err(e) => dev_warn!(pdev.as_ref(), "GPU name unavailable: {:?}\n", e),
+ Ok(name) => dev_info!(pdev, "GPU name: {}\n", name),
+ Err(e) => dev_warn!(pdev, "GPU name unavailable: {:?}\n", e),
}
Ok(())
diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index 03a4f3599849..5da153c71800 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -237,21 +237,27 @@ fn new(dev: &device::Device<device::Bound>) -> Result<Self> {
// PANIC: per the invariant of `cpu_write_ptr`, `tx` is `<= MSGQ_NUM_PAGES`.
let (before_tx, after_tx) = gsp_mem.cpuq.msgq.data.split_at_mut(tx);
- if rx <= tx {
- // The area from `tx` up to the end of the ring, and from the beginning of the ring up
- // to `rx`, minus one unit, belongs to the driver.
- if rx == 0 {
- let last = after_tx.len() - 1;
- (&mut after_tx[..last], &mut before_tx[0..0])
- } else {
- (after_tx, &mut before_tx[..rx])
- }
+ // The area starting at `tx` and ending at `rx - 2` modulo MSGQ_NUM_PAGES, inclusive,
+ // belongs to the driver for writing.
+
+ if rx == 0 {
+ // Since `rx` is zero, leave an empty slot at end of the buffer.
+ let last = after_tx.len() - 1;
+ (&mut after_tx[..last], &mut [])
+ } else if rx <= tx {
+ // The area is discontiguous and we leave an empty slot before `rx`.
+ // PANIC:
+ // - The index `rx - 1` is non-negative because `rx != 0` in this branch.
+ // - The index does not exceed `before_tx.len()` (which equals `tx`) because
+ // `rx <= tx` in this branch.
+ (after_tx, &mut before_tx[..(rx - 1)])
} else {
- // The area from `tx` to `rx`, minus one unit, belongs to the driver.
- //
- // PANIC: per the invariants of `cpu_write_ptr` and `gsp_read_ptr`, `rx` and `tx` are
- // `<= MSGQ_NUM_PAGES`, and the test above ensured that `rx > tx`.
- (after_tx.split_at_mut(rx - tx).0, &mut before_tx[0..0])
+ // The area is contiguous and we leave an empty slot before `rx`.
+ // PANIC:
+ // - The index `rx - tx - 1` is non-negative because `rx > tx` in this branch.
+ // - The index does not exceed `after_tx.len()` (which is `MSGQ_NUM_PAGES - tx`)
+ // because `rx < MSGQ_NUM_PAGES` by the `gsp_read_ptr` invariant.
+ (&mut after_tx[..(rx - tx - 1)], &mut [])
}
}
@@ -273,8 +279,8 @@ fn new(dev: &device::Device<device::Bound>) -> Result<Self> {
let (before_rx, after_rx) = gsp_mem.gspq.msgq.data.split_at(rx);
match tx.cmp(&rx) {
- cmp::Ordering::Equal => (&after_rx[0..0], &after_rx[0..0]),
- cmp::Ordering::Greater => (&after_rx[..tx], &before_rx[0..0]),
+ cmp::Ordering::Equal => (&[], &[]),
+ cmp::Ordering::Greater => (&after_rx[..tx], &[]),
cmp::Ordering::Less => (after_rx, &before_rx[..tx]),
}
}
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c
index 50c7b45c59e3..d0130658091b 100644
--- a/drivers/hid/bpf/hid_bpf_dispatch.c
+++ b/drivers/hid/bpf/hid_bpf_dispatch.c
@@ -24,7 +24,8 @@ EXPORT_SYMBOL(hid_ops);
u8 *
dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type, u8 *data,
- u32 *size, int interrupt, u64 source, bool from_bpf)
+ size_t *buf_size, u32 *size, int interrupt, u64 source,
+ bool from_bpf)
{
struct hid_bpf_ctx_kern ctx_kern = {
.ctx = {
@@ -74,6 +75,7 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type
*size = ret;
}
+ *buf_size = ctx_kern.ctx.allocated_size;
return ctx_kern.data;
}
EXPORT_SYMBOL_GPL(dispatch_hid_bpf_device_event);
@@ -505,7 +507,7 @@ __hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *b
if (ret)
return ret;
- return hid_ops->hid_input_report(ctx->hid, type, buf, size, 0, (u64)(long)ctx, true,
+ return hid_ops->hid_input_report(ctx->hid, type, buf, size, size, 0, (u64)(long)ctx, true,
lock_already_taken);
}
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index bc93b27f9b13..b2332efabeb5 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -1163,7 +1163,8 @@ static int asus_start_multitouch(struct hid_device *hdev)
return 0;
}
-static int __maybe_unused asus_resume(struct hid_device *hdev) {
+static int __maybe_unused asus_resume(struct hid_device *hdev)
+{
struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
int ret = 0;
@@ -1311,22 +1312,17 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
* were freed during registration due to no usages being mapped,
* leaving drvdata->input pointing to freed memory.
*/
- if (!drvdata->input || !(hdev->claimed & HID_CLAIMED_INPUT)) {
- hid_err(hdev, "Asus input not registered\n");
- ret = -ENOMEM;
- goto err_stop_hw;
- }
-
- if (drvdata->tp) {
- drvdata->input->name = "Asus TouchPad";
- } else {
- drvdata->input->name = "Asus Keyboard";
- }
+ if (drvdata->input && (hdev->claimed & HID_CLAIMED_INPUT)) {
+ if (drvdata->tp)
+ drvdata->input->name = "Asus TouchPad";
+ else
+ drvdata->input->name = "Asus Keyboard";
- if (drvdata->tp) {
- ret = asus_start_multitouch(hdev);
- if (ret)
- goto err_stop_hw;
+ if (drvdata->tp) {
+ ret = asus_start_multitouch(hdev);
+ if (ret)
+ goto err_stop_hw;
+ }
}
return 0;
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 868c65684aa8..570884039d78 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2029,24 +2029,32 @@ int __hid_request(struct hid_device *hid, struct hid_report *report,
}
EXPORT_SYMBOL_GPL(__hid_request);
-int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size,
- int interrupt)
+int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *data,
+ size_t bufsize, u32 size, int interrupt)
{
struct hid_report_enum *report_enum = hid->report_enum + type;
struct hid_report *report;
struct hid_driver *hdrv;
int max_buffer_size = HID_MAX_BUFFER_SIZE;
u32 rsize, csize = size;
+ size_t bsize = bufsize;
u8 *cdata = data;
int ret = 0;
report = hid_get_report(report_enum, data);
if (!report)
- goto out;
+ return 0;
+
+ if (unlikely(bsize < csize)) {
+ hid_warn_ratelimited(hid, "Event data for report %d is incorrect (%d vs %zu)\n",
+ report->id, csize, bsize);
+ return -EINVAL;
+ }
if (report_enum->numbered) {
cdata++;
csize--;
+ bsize--;
}
rsize = hid_compute_report_size(report);
@@ -2059,11 +2067,16 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
else if (rsize > max_buffer_size)
rsize = max_buffer_size;
+ if (bsize < rsize) {
+ hid_warn_ratelimited(hid, "Event data for report %d was too short (%d vs %zu)\n",
+ report->id, rsize, bsize);
+ return -EINVAL;
+ }
+
if (csize < rsize) {
- hid_warn_ratelimited(hid, "Event data for report %d was too short (%d vs %d)\n",
- report->id, rsize, csize);
- ret = -EINVAL;
- goto out;
+ dbg_hid("report %d is too short, (%d < %d)\n", report->id,
+ csize, rsize);
+ memset(cdata + csize, 0, rsize - csize);
}
if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
@@ -2071,7 +2084,7 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
if (hid->claimed & HID_CLAIMED_HIDRAW) {
ret = hidraw_report_event(hid, data, size);
if (ret)
- goto out;
+ return ret;
}
if (hid->claimed != HID_CLAIMED_HIDRAW && report->maxfield) {
@@ -2083,15 +2096,15 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
if (hid->claimed & HID_CLAIMED_INPUT)
hidinput_report_event(hid, report);
-out:
+
return ret;
}
EXPORT_SYMBOL_GPL(hid_report_raw_event);
static int __hid_input_report(struct hid_device *hid, enum hid_report_type type,
- u8 *data, u32 size, int interrupt, u64 source, bool from_bpf,
- bool lock_already_taken)
+ u8 *data, size_t bufsize, u32 size, int interrupt, u64 source,
+ bool from_bpf, bool lock_already_taken)
{
struct hid_report_enum *report_enum;
struct hid_driver *hdrv;
@@ -2116,7 +2129,8 @@ static int __hid_input_report(struct hid_device *hid, enum hid_report_type type,
report_enum = hid->report_enum + type;
hdrv = hid->driver;
- data = dispatch_hid_bpf_device_event(hid, type, data, &size, interrupt, source, from_bpf);
+ data = dispatch_hid_bpf_device_event(hid, type, data, &bufsize, &size, interrupt,
+ source, from_bpf);
if (IS_ERR(data)) {
ret = PTR_ERR(data);
goto unlock;
@@ -2145,7 +2159,7 @@ static int __hid_input_report(struct hid_device *hid, enum hid_report_type type,
goto unlock;
}
- ret = hid_report_raw_event(hid, type, data, size, interrupt);
+ ret = hid_report_raw_event(hid, type, data, bufsize, size, interrupt);
unlock:
if (!lock_already_taken)
@@ -2163,16 +2177,41 @@ static int __hid_input_report(struct hid_device *hid, enum hid_report_type type,
* @interrupt: distinguish between interrupt and control transfers
*
* This is data entry for lower layers.
+ * Legacy, please use hid_safe_input_report() instead.
*/
int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size,
int interrupt)
{
- return __hid_input_report(hid, type, data, size, interrupt, 0,
+ return __hid_input_report(hid, type, data, size, size, interrupt, 0,
false, /* from_bpf */
false /* lock_already_taken */);
}
EXPORT_SYMBOL_GPL(hid_input_report);
+/**
+ * hid_safe_input_report - report data from lower layer (usb, bt...)
+ *
+ * @hid: hid device
+ * @type: HID report type (HID_*_REPORT)
+ * @data: report contents
+ * @bufsize: allocated size of the data buffer
+ * @size: useful size of data parameter
+ * @interrupt: distinguish between interrupt and control transfers
+ *
+ * This is data entry for lower layers.
+ * Please use this function instead of the non safe version because we provide
+ * here the size of the buffer, allowing hid-core to make smarter decisions
+ * regarding the incoming buffer.
+ */
+int hid_safe_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data,
+ size_t bufsize, u32 size, int interrupt)
+{
+ return __hid_input_report(hid, type, data, bufsize, size, interrupt, 0,
+ false, /* from_bpf */
+ false /* lock_already_taken */);
+}
+EXPORT_SYMBOL_GPL(hid_safe_input_report);
+
bool hid_match_one_id(const struct hid_device *hdev,
const struct hid_device_id *id)
{
diff --git a/drivers/hid/hid-gfrm.c b/drivers/hid/hid-gfrm.c
index 699186ff2349..d2a56bf92b41 100644
--- a/drivers/hid/hid-gfrm.c
+++ b/drivers/hid/hid-gfrm.c
@@ -66,7 +66,7 @@ static int gfrm_raw_event(struct hid_device *hdev, struct hid_report *report,
switch (data[1]) {
case GFRM100_SEARCH_KEY_DOWN:
ret = hid_report_raw_event(hdev, HID_INPUT_REPORT, search_key_dn,
- sizeof(search_key_dn), 1);
+ sizeof(search_key_dn), sizeof(search_key_dn), 1);
break;
case GFRM100_SEARCH_KEY_AUDIO_DATA:
@@ -74,7 +74,7 @@ static int gfrm_raw_event(struct hid_device *hdev, struct hid_report *report,
case GFRM100_SEARCH_KEY_UP:
ret = hid_report_raw_event(hdev, HID_INPUT_REPORT, search_key_up,
- sizeof(search_key_up), 1);
+ sizeof(search_key_up), sizeof(search_key_up), 1);
break;
default:
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index d1dea7297712..e9aa99ade5aa 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -3665,7 +3665,7 @@ static int hidpp10_consumer_keys_raw_event(struct hidpp_device *hidpp,
memcpy(&consumer_report[1], &data[3], 4);
/* We are called from atomic context */
hid_report_raw_event(hidpp->hid_dev, HID_INPUT_REPORT,
- consumer_report, 5, 1);
+ consumer_report, sizeof(consumer_report), 5, 1);
return 1;
}
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index e82a3c4e5b44..eeab0b6e32cc 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -533,7 +533,7 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
}
ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf,
- size, 0);
+ size, size, 0);
if (ret)
dev_warn(&hdev->dev, "failed to report feature\n");
}
diff --git a/drivers/hid/hid-primax.c b/drivers/hid/hid-primax.c
index e44d79dff8de..8db054280afb 100644
--- a/drivers/hid/hid-primax.c
+++ b/drivers/hid/hid-primax.c
@@ -44,7 +44,7 @@ static int px_raw_event(struct hid_device *hid, struct hid_report *report,
data[0] |= (1 << (data[idx] - 0xE0));
data[idx] = 0;
}
- hid_report_raw_event(hid, HID_INPUT_REPORT, data, size, 0);
+ hid_report_raw_event(hid, HID_INPUT_REPORT, data, size, size, 0);
return 1;
default: /* unknown report */
diff --git a/drivers/hid/hid-vivaldi-common.c b/drivers/hid/hid-vivaldi-common.c
index bf734055d4b6..b12bb5cc091a 100644
--- a/drivers/hid/hid-vivaldi-common.c
+++ b/drivers/hid/hid-vivaldi-common.c
@@ -85,7 +85,7 @@ void vivaldi_feature_mapping(struct hid_device *hdev,
}
ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, report_data,
- report_len, 0);
+ report_len, report_len, 0);
if (ret) {
dev_warn(&hdev->dev, "failed to report feature %d\n",
field->report->id);
diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
index 5a183af3d5c6..e0a302544cef 100644
--- a/drivers/hid/i2c-hid/i2c-hid-core.c
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -574,9 +574,10 @@ static void i2c_hid_get_input(struct i2c_hid *ihid)
if (ihid->hid->group != HID_GROUP_RMI)
pm_wakeup_event(&ihid->client->dev, 0);
- hid_input_report(ihid->hid, HID_INPUT_REPORT,
- ihid->inbuf + sizeof(__le16),
- ret_size - sizeof(__le16), 1);
+ hid_safe_input_report(ihid->hid, HID_INPUT_REPORT,
+ ihid->inbuf + sizeof(__le16),
+ ihid->bufsize - sizeof(__le16),
+ ret_size - sizeof(__le16), 1);
}
return;
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index ddd5d77fb5a5..047d390d5aae 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -283,9 +283,9 @@ static void hid_irq_in(struct urb *urb)
break;
usbhid_mark_busy(usbhid);
if (!test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
- hid_input_report(urb->context, HID_INPUT_REPORT,
- urb->transfer_buffer,
- urb->actual_length, 1);
+ hid_safe_input_report(urb->context, HID_INPUT_REPORT,
+ urb->transfer_buffer, urb->transfer_buffer_length,
+ urb->actual_length, 1);
/*
* autosuspend refused while keys are pressed
* because most keyboards don't wake up when
@@ -482,9 +482,10 @@ static void hid_ctrl(struct urb *urb)
switch (status) {
case 0: /* success */
if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
- hid_input_report(urb->context,
+ hid_safe_input_report(urb->context,
usbhid->ctrl[usbhid->ctrltail].report->type,
- urb->transfer_buffer, urb->actual_length, 0);
+ urb->transfer_buffer, urb->transfer_buffer_length,
+ urb->actual_length, 0);
break;
case -ESHUTDOWN: /* unplug */
unplug = 1;
@@ -1552,7 +1553,7 @@ static int hid_post_reset(struct usb_interface *intf)
* configuration descriptors passed, we already know that
* the size of the HID report descriptor has not changed.
*/
- rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL);
+ rdesc = kmalloc(hid->dev_rsize, GFP_NOIO);
if (!rdesc)
return -ENOMEM;
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 0d1c6d90fe21..a32320b351e3 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -90,7 +90,7 @@ static void wacom_wac_queue_flush(struct hid_device *hdev,
kfree(buf);
continue;
}
- err = hid_report_raw_event(hdev, HID_INPUT_REPORT, buf, size, false);
+ err = hid_report_raw_event(hdev, HID_INPUT_REPORT, buf, size, size, false);
if (err) {
hid_warn(hdev, "%s: unable to flush event due to error %d\n",
__func__, err);
@@ -334,7 +334,7 @@ static void wacom_feature_mapping(struct hid_device *hdev,
data, n, WAC_CMD_RETRIES);
if (ret == n && features->type == HID_GENERIC) {
ret = hid_report_raw_event(hdev,
- HID_FEATURE_REPORT, data, n, 0);
+ HID_FEATURE_REPORT, data, n, n, 0);
} else if (ret == 2 && features->type != HID_GENERIC) {
features->touch_max = data[1];
} else {
@@ -395,7 +395,7 @@ static void wacom_feature_mapping(struct hid_device *hdev,
data, n, WAC_CMD_RETRIES);
if (ret == n) {
ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT,
- data, n, 0);
+ data, n, n, 0);
} else {
hid_warn(hdev, "%s: could not retrieve sensor offsets\n",
__func__);
diff --git a/drivers/hte/Kconfig b/drivers/hte/Kconfig
index 641af722b555..f57bad67deef 100644
--- a/drivers/hte/Kconfig
+++ b/drivers/hte/Kconfig
@@ -16,13 +16,13 @@ if HTE
config HTE_TEGRA194
tristate "NVIDIA Tegra194 HTE Support"
- depends on (ARCH_TEGRA_194_SOC || COMPILE_TEST)
+ depends on (ARCH_TEGRA || COMPILE_TEST)
depends on GPIOLIB
help
Enable this option for integrated hardware timestamping engine also
known as generic timestamping engine (GTE) support on NVIDIA Tegra194
- systems-on-chip. The driver supports 352 LIC IRQs and 39 AON GPIOs
- lines for timestamping in realtime.
+ and later systems-on-chip. The driver supports 352 LIC IRQs and 39
+ AON GPIOs lines for timestamping in realtime.
config HTE_TEGRA194_TEST
tristate "NVIDIA Tegra194 HTE Test"
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index bc4fc1951ae1..3d2827477f0a 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -1430,7 +1430,6 @@ static int vmbus_alloc_synic_and_connect(void)
{
int ret, cpu;
struct work_struct __percpu *works;
- int hyperv_cpuhp_online;
ret = hv_synic_alloc();
if (ret < 0)
diff --git a/drivers/hwmon/aspeed-g6-pwm-tach.c b/drivers/hwmon/aspeed-g6-pwm-tach.c
index 44e1ecba205d..4f6e6d440dd4 100644
--- a/drivers/hwmon/aspeed-g6-pwm-tach.c
+++ b/drivers/hwmon/aspeed-g6-pwm-tach.c
@@ -517,13 +517,6 @@ static int aspeed_pwm_tach_probe(struct platform_device *pdev)
return 0;
}
-static void aspeed_pwm_tach_remove(struct platform_device *pdev)
-{
- struct aspeed_pwm_tach_data *priv = platform_get_drvdata(pdev);
-
- reset_control_assert(priv->reset);
-}
-
static const struct of_device_id aspeed_pwm_tach_match[] = {
{
.compatible = "aspeed,ast2600-pwm-tach",
@@ -537,7 +530,6 @@ MODULE_DEVICE_TABLE(of, aspeed_pwm_tach_match);
static struct platform_driver aspeed_pwm_tach_driver = {
.probe = aspeed_pwm_tach_probe,
- .remove = aspeed_pwm_tach_remove,
.driver = {
.name = "aspeed-g6-pwm-tach",
.of_match_table = aspeed_pwm_tach_match,
diff --git a/drivers/i3c/master/adi-i3c-master.c b/drivers/i3c/master/adi-i3c-master.c
index 6616f751075a..545ddd79a45d 100644
--- a/drivers/i3c/master/adi-i3c-master.c
+++ b/drivers/i3c/master/adi-i3c-master.c
@@ -361,7 +361,7 @@ static int adi_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
cmd->err = adi_i3c_cmd_get_err(&xfer->cmds[0]);
- return 0;
+ return xfer->ret;
}
static int adi_i3c_master_i3c_xfers(struct i3c_dev_desc *dev,
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index d6bdb32397fb..259e4f527665 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -7,6 +7,7 @@
#include <linux/bitfield.h>
#include <linux/bitops.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/err.h>
@@ -924,7 +925,6 @@ static int dw_i3c_master_i3c_xfers(struct i3c_dev_desc *dev,
struct i3c_master_controller *m = i3c_dev_get_master(dev);
struct dw_i3c_master *master = to_dw_i3c_master(m);
unsigned int nrxwords = 0, ntxwords = 0;
- struct dw_i3c_xfer *xfer;
int i, ret = 0;
if (!i3c_nxfers)
@@ -944,7 +944,7 @@ static int dw_i3c_master_i3c_xfers(struct i3c_dev_desc *dev,
nrxwords > master->caps.datafifodepth)
return -EOPNOTSUPP;
- xfer = dw_i3c_master_alloc_xfer(master, i3c_nxfers);
+ struct dw_i3c_xfer *xfer __free(kfree) = dw_i3c_master_alloc_xfer(master, i3c_nxfers);
if (!xfer)
return -ENOMEM;
@@ -995,7 +995,6 @@ static int dw_i3c_master_i3c_xfers(struct i3c_dev_desc *dev,
}
ret = xfer->ret;
- dw_i3c_master_free_xfer(xfer);
pm_runtime_put_autosuspend(master->dev);
return ret;
@@ -1606,13 +1605,11 @@ int dw_i3c_common_probe(struct dw_i3c_master *master,
if (IS_ERR(master->pclk))
return PTR_ERR(master->pclk);
- master->core_rst = devm_reset_control_get_optional_exclusive(&pdev->dev,
- "core_rst");
+ master->core_rst = devm_reset_control_get_optional_exclusive_deasserted(&pdev->dev,
+ "core_rst");
if (IS_ERR(master->core_rst))
return PTR_ERR(master->core_rst);
- reset_control_deassert(master->core_rst);
-
spin_lock_init(&master->xferqueue.lock);
INIT_LIST_HEAD(&master->xferqueue.list);
@@ -1624,7 +1621,7 @@ int dw_i3c_common_probe(struct dw_i3c_master *master,
dw_i3c_master_irq_handler, 0,
dev_name(&pdev->dev), master);
if (ret)
- goto err_assert_rst;
+ return ret;
platform_set_drvdata(pdev, master);
@@ -1669,13 +1666,12 @@ int dw_i3c_common_probe(struct dw_i3c_master *master,
return 0;
err_disable_pm:
+ if (master->quirks & DW_I3C_DISABLE_RUNTIME_PM_QUIRK)
+ pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
-err_assert_rst:
- reset_control_assert(master->core_rst);
-
return ret;
}
EXPORT_SYMBOL_GPL(dw_i3c_common_probe);
diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c
index e487ef52f6b4..e4daaa612055 100644
--- a/drivers/i3c/master/mipi-i3c-hci/dma.c
+++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
@@ -754,7 +754,10 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh)
if (!(ibi_status & IBI_LAST_STATUS)) {
ibi_size += chunks * rh->ibi_chunk_sz;
} else {
- ibi_size += FIELD_GET(IBI_DATA_LENGTH, ibi_status);
+ if (chunks) {
+ ibi_size += (chunks - 1) * rh->ibi_chunk_sz;
+ ibi_size += FIELD_GET(IBI_DATA_LENGTH, ibi_status);
+ }
last_ptr = ptr;
break;
}
diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index d9f5b30a4b2f..a8a9e89a9710 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -8,6 +8,7 @@
#include <linux/bitfield.h>
#include <linux/bitops.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/err.h>
@@ -817,13 +818,12 @@ static int renesas_i3c_i3c_xfers(struct i3c_dev_desc *dev, struct i3c_xfer *i3c_
struct i3c_master_controller *m = i3c_dev_get_master(dev);
struct renesas_i3c *i3c = to_renesas_i3c(m);
struct renesas_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
- struct renesas_i3c_xfer *xfer;
int i;
/* Enable I3C bus. */
renesas_i3c_bus_enable(m, true);
- xfer = renesas_i3c_alloc_xfer(i3c, 1);
+ struct renesas_i3c_xfer *xfer __free(kfree) = renesas_i3c_alloc_xfer(i3c, 1);
if (!xfer)
return -ENOMEM;
diff --git a/drivers/infiniband/core/iwpm_msg.c b/drivers/infiniband/core/iwpm_msg.c
index 69c85249b465..4625abd29ac0 100644
--- a/drivers/infiniband/core/iwpm_msg.c
+++ b/drivers/infiniband/core/iwpm_msg.c
@@ -365,9 +365,9 @@ int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client)
/* netlink attribute policy for the received response to register pid request */
static const struct nla_policy resp_reg_policy[IWPM_NLA_RREG_PID_MAX] = {
[IWPM_NLA_RREG_PID_SEQ] = { .type = NLA_U32 },
- [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_STRING,
+ [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_NUL_STRING,
.len = IWPM_DEVNAME_SIZE - 1 },
- [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_STRING,
+ [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_NUL_STRING,
.len = IWPM_ULIBNAME_SIZE - 1 },
[IWPM_NLA_RREG_ULIB_VER] = { .type = NLA_U16 },
[IWPM_NLA_RREG_PID_ERR] = { .type = NLA_U16 }
@@ -677,7 +677,7 @@ int iwpm_remote_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
/* netlink attribute policy for the received request for mapping info */
static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = {
- [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING,
+ [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_NUL_STRING,
.len = IWPM_ULIBNAME_SIZE - 1 },
[IWPM_NLA_MAPINFO_ULIB_VER] = { .type = NLA_U16 }
};
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index edc34c69f0f2..acf4ce2891b7 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -55,8 +55,7 @@ static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int d
if (dirty)
ib_dma_unmap_sgtable_attrs(dev, &umem->sgt_append.sgt,
- DMA_BIDIRECTIONAL,
- DMA_ATTR_REQUIRE_COHERENT);
+ DMA_BIDIRECTIONAL, umem->dma_attrs);
for_each_sgtable_sg(&umem->sgt_append.sgt, sg, i) {
unpin_user_page_range_dirty_lock(sg_page(sg),
@@ -170,7 +169,6 @@ struct ib_umem *ib_umem_get(struct ib_device *device, unsigned long addr,
unsigned long lock_limit;
unsigned long new_pinned;
unsigned long cur_base;
- unsigned long dma_attr = DMA_ATTR_REQUIRE_COHERENT;
struct mm_struct *mm;
unsigned long npages;
int pinned, ret;
@@ -203,6 +201,10 @@ struct ib_umem *ib_umem_get(struct ib_device *device, unsigned long addr,
umem->iova = addr;
umem->writable = ib_access_writable(access);
umem->owning_mm = mm = current->mm;
+ umem->dma_attrs = DMA_ATTR_REQUIRE_COHERENT;
+ if (access & IB_ACCESS_RELAXED_ORDERING)
+ umem->dma_attrs |= DMA_ATTR_WEAK_ORDERING;
+
mmgrab(mm);
page_list = (struct page **) __get_free_page(GFP_KERNEL);
@@ -255,11 +257,8 @@ struct ib_umem *ib_umem_get(struct ib_device *device, unsigned long addr,
}
}
- if (access & IB_ACCESS_RELAXED_ORDERING)
- dma_attr |= DMA_ATTR_WEAK_ORDERING;
-
ret = ib_dma_map_sgtable_attrs(device, &umem->sgt_append.sgt,
- DMA_BIDIRECTIONAL, dma_attr);
+ DMA_BIDIRECTIONAL, umem->dma_attrs);
if (ret)
goto umem_release;
goto out;
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 760d5f4623b5..72f1f6e28138 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -351,8 +351,12 @@ static struct amd_iommu *__rlookup_amd_iommu(u16 seg, u16 devid)
struct amd_iommu_pci_seg *pci_seg;
for_each_pci_segment(pci_seg) {
- if (pci_seg->id == seg)
- return pci_seg->rlookup_table[devid];
+ if (pci_seg->id != seg)
+ continue;
+ /* IVRS may not describe every device on the bus */
+ if (devid > pci_seg->last_bdf)
+ return NULL;
+ return pci_seg->rlookup_table[devid];
}
return NULL;
}
@@ -403,11 +407,12 @@ struct iommu_dev_data *search_dev_data(struct amd_iommu *iommu, u16 devid)
return NULL;
}
-static int clone_alias(struct pci_dev *pdev, u16 alias, void *data)
+static int clone_alias(struct pci_dev *pdev_origin, u16 alias, void *data)
{
struct dev_table_entry new;
struct amd_iommu *iommu;
struct iommu_dev_data *dev_data, *alias_data;
+ struct pci_dev *pdev = data;
u16 devid = pci_dev_id(pdev);
int ret = 0;
@@ -454,9 +459,9 @@ static void clone_aliases(struct amd_iommu *iommu, struct device *dev)
* part of the PCI DMA aliases if it's bus differs
* from the original device.
*/
- clone_alias(pdev, iommu->pci_seg->alias_table[pci_dev_id(pdev)], NULL);
+ clone_alias(pdev, iommu->pci_seg->alias_table[pci_dev_id(pdev)], pdev);
- pci_for_each_dma_alias(pdev, clone_alias, NULL);
+ pci_for_each_dma_alias(pdev, clone_alias, pdev);
}
static void setup_aliases(struct amd_iommu *iommu, struct device *dev)
diff --git a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
index 6fe5563eaf9e..83f6e9f6c51d 100644
--- a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
+++ b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
@@ -479,6 +479,10 @@ static int tegra241_vcmdq_hw_init(struct tegra241_vcmdq *vcmdq)
/* Reset VCMDQ */
tegra241_vcmdq_hw_deinit(vcmdq);
+ /* vintf->hyp_own is a HW state finalized in tegra241_vintf_hw_init() */
+ if (!vcmdq->vintf->hyp_own)
+ vcmdq->cmdq.supports_cmd = tegra241_guest_vcmdq_supports_cmd;
+
/* Configure and enable VCMDQ */
writeq_relaxed(vcmdq->cmdq.q.q_base, REG_VCMDQ_PAGE1(vcmdq, BASE));
@@ -639,9 +643,6 @@ static int tegra241_vcmdq_alloc_smmu_cmdq(struct tegra241_vcmdq *vcmdq)
q->q_base = q->base_dma & VCMDQ_ADDR;
q->q_base |= FIELD_PREP(VCMDQ_LOG2SIZE, q->llq.max_n_shift);
- if (!vcmdq->vintf->hyp_own)
- cmdq->supports_cmd = tegra241_guest_vcmdq_supports_cmd;
-
return arm_smmu_cmdq_init(smmu, cmdq);
}
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index ef7613b177b9..88fabca898bb 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -3529,8 +3529,8 @@ void domain_remove_dev_pasid(struct iommu_domain *domain,
if (!domain)
return;
- /* Identity domain has no meta data for pasid. */
- if (domain->type == IOMMU_DOMAIN_IDENTITY)
+ /* Identity domain and blocked domain have no meta data for pasid. */
+ if (domain->type == IOMMU_DOMAIN_IDENTITY || domain->type == IOMMU_DOMAIN_BLOCKED)
return;
dmar_domain = to_dmar_domain(domain);
@@ -3544,12 +3544,13 @@ void domain_remove_dev_pasid(struct iommu_domain *domain,
}
spin_unlock_irqrestore(&dmar_domain->lock, flags);
+ if (WARN_ON_ONCE(!dev_pasid))
+ return;
+
cache_tag_unassign_domain(dmar_domain, dev, pasid);
domain_detach_iommu(dmar_domain, iommu);
- if (!WARN_ON_ONCE(!dev_pasid)) {
- intel_iommu_debugfs_remove_dev_pasid(dev_pasid);
- kfree(dev_pasid);
- }
+ intel_iommu_debugfs_remove_dev_pasid(dev_pasid);
+ kfree(dev_pasid);
}
static int blocking_domain_set_dev_pasid(struct iommu_domain *domain,
@@ -3933,6 +3934,9 @@ static void quirk_iommu_igfx(struct pci_dev *dev)
disable_igfx_iommu = 1;
}
+/* Q35 integrated gfx dmar support is totally busted. */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x29b2, quirk_iommu_igfx);
+
/* G4x/GM45 integrated gfx dmar support is totally busted. */
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx);
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index ee83850c7060..ef08c2c4ec95 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -61,14 +61,14 @@ struct iommu_group {
int id;
struct iommu_domain *default_domain;
struct iommu_domain *blocking_domain;
- /*
- * During a group device reset, @resetting_domain points to the physical
- * domain, while @domain points to the attached domain before the reset.
- */
- struct iommu_domain *resetting_domain;
struct iommu_domain *domain;
struct list_head entry;
unsigned int owner_cnt;
+ /*
+ * Number of devices in the group undergoing or awaiting recovery.
+ * If non-zero, concurrent domain attachments are rejected.
+ */
+ unsigned int recovery_cnt;
void *owner;
};
@@ -76,12 +76,33 @@ struct group_device {
struct list_head list;
struct device *dev;
char *name;
+ /*
+ * Device is blocked for a pending recovery while its group->domain is
+ * retained. This can happen when:
+ * - Device is undergoing a reset
+ */
+ bool blocked;
+ unsigned int reset_depth;
};
/* Iterate over each struct group_device in a struct iommu_group */
#define for_each_group_device(group, pos) \
list_for_each_entry(pos, &(group)->devices, list)
+static struct group_device *__dev_to_gdev(struct device *dev)
+{
+ struct iommu_group *group = dev->iommu_group;
+ struct group_device *gdev;
+
+ lockdep_assert_held(&group->mutex);
+
+ for_each_group_device(group, gdev) {
+ if (gdev->dev == dev)
+ return gdev;
+ }
+ return NULL;
+}
+
struct iommu_group_attribute {
struct attribute attr;
ssize_t (*show)(struct iommu_group *group, char *buf);
@@ -2195,6 +2216,8 @@ EXPORT_SYMBOL_GPL(iommu_attach_device);
int iommu_deferred_attach(struct device *dev, struct iommu_domain *domain)
{
+ struct group_device *gdev;
+
/*
* This is called on the dma mapping fast path so avoid locking. This is
* racy, but we have an expectation that the driver will setup its DMAs
@@ -2205,14 +2228,18 @@ int iommu_deferred_attach(struct device *dev, struct iommu_domain *domain)
guard(mutex)(&dev->iommu_group->mutex);
+ gdev = __dev_to_gdev(dev);
+ if (WARN_ON(!gdev))
+ return -ENODEV;
+
/*
- * This is a concurrent attach during a device reset. Reject it until
+ * This is a concurrent attach during device recovery. Reject it until
* pci_dev_reset_iommu_done() attaches the device to group->domain.
*
* Note that this might fail the iommu_dma_map(). But there's nothing
* more we can do here.
*/
- if (dev->iommu_group->resetting_domain)
+ if (gdev->blocked)
return -EBUSY;
return __iommu_attach_device(domain, dev, NULL);
}
@@ -2269,19 +2296,24 @@ EXPORT_SYMBOL_GPL(iommu_get_domain_for_dev);
struct iommu_domain *iommu_driver_get_domain_for_dev(struct device *dev)
{
struct iommu_group *group = dev->iommu_group;
+ struct group_device *gdev;
lockdep_assert_held(&group->mutex);
+ gdev = __dev_to_gdev(dev);
+ if (WARN_ON(!gdev))
+ return NULL;
+
/*
* Driver handles the low-level __iommu_attach_device(), including the
* one invoked by pci_dev_reset_iommu_done() re-attaching the device to
* the cached group->domain. In this case, the driver must get the old
- * domain from group->resetting_domain rather than group->domain. This
+ * domain from group->blocking_domain rather than group->domain. This
* prevents it from re-attaching the device from group->domain (old) to
* group->domain (new).
*/
- if (group->resetting_domain)
- return group->resetting_domain;
+ if (gdev->blocked)
+ return group->blocking_domain;
return group->domain;
}
@@ -2440,10 +2472,11 @@ static int __iommu_group_set_domain_internal(struct iommu_group *group,
return -EINVAL;
/*
- * This is a concurrent attach during a device reset. Reject it until
- * pci_dev_reset_iommu_done() attaches the device to group->domain.
+ * This is a concurrent attach during device recovery. Reject it until
+ * pci_dev_reset_iommu_done() attaches the device to group->domain, if
+ * IOMMU_SET_DOMAIN_MUST_SUCCEED is not set.
*/
- if (group->resetting_domain)
+ if (group->recovery_cnt && !(flags & IOMMU_SET_DOMAIN_MUST_SUCCEED))
return -EBUSY;
/*
@@ -2454,6 +2487,13 @@ static int __iommu_group_set_domain_internal(struct iommu_group *group,
*/
result = 0;
for_each_group_device(group, gdev) {
+ /*
+ * Device under recovery is attached to group->blocking_domain.
+ * Don't change that. pci_dev_reset_iommu_done() will re-attach
+ * its domain to the updated group->domain, after the recovery.
+ */
+ if (gdev->blocked)
+ continue;
ret = __iommu_device_set_domain(group, gdev->dev, new_domain,
group->domain, flags);
if (ret) {
@@ -3532,7 +3572,12 @@ static void __iommu_remove_group_pasid(struct iommu_group *group,
struct group_device *device;
for_each_group_device(group, device) {
- if (device->dev->iommu->max_pasids > 0)
+ /*
+ * A group-level detach cannot fail, even if there is a blocked
+ * device. In fact, blocked devices must be already detached for
+ * a pending device recovery.
+ */
+ if (!device->blocked && device->dev->iommu->max_pasids > 0)
iommu_remove_dev_pasid(device->dev, pasid, domain);
}
}
@@ -3577,10 +3622,10 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
mutex_lock(&group->mutex);
/*
- * This is a concurrent attach during a device reset. Reject it until
+ * This is a concurrent attach during device recovery. Reject it until
* pci_dev_reset_iommu_done() attaches the device to group->domain.
*/
- if (group->resetting_domain) {
+ if (group->recovery_cnt) {
ret = -EBUSY;
goto out_unlock;
}
@@ -3670,10 +3715,10 @@ int iommu_replace_device_pasid(struct iommu_domain *domain,
mutex_lock(&group->mutex);
/*
- * This is a concurrent attach during a device reset. Reject it until
+ * This is a concurrent attach during device recovery. Reject it until
* pci_dev_reset_iommu_done() attaches the device to group->domain.
*/
- if (group->resetting_domain) {
+ if (group->recovery_cnt) {
ret = -EBUSY;
goto out_unlock;
}
@@ -3944,12 +3989,12 @@ EXPORT_SYMBOL_NS_GPL(iommu_replace_group_handle, "IOMMUFD_INTERNAL");
* routine wants to block any IOMMU activity: translation and ATS invalidation.
*
* This function attaches the device's RID/PASID(s) the group->blocking_domain,
- * setting the group->resetting_domain. This allows the IOMMU driver pausing any
+ * incrementing the group->recovery_cnt, to allow the IOMMU driver pausing any
* IOMMU activity while leaving the group->domain pointer intact. Later when the
* reset is finished, pci_dev_reset_iommu_done() can restore everything.
*
* Caller must use pci_dev_reset_iommu_prepare() with pci_dev_reset_iommu_done()
- * before/after the core-level reset routine, to unset the resetting_domain.
+ * before/after the core-level reset routine, to decrement the recovery_cnt.
*
* Return: 0 on success or negative error code if the preparation failed.
*
@@ -3962,6 +4007,7 @@ EXPORT_SYMBOL_NS_GPL(iommu_replace_group_handle, "IOMMUFD_INTERNAL");
int pci_dev_reset_iommu_prepare(struct pci_dev *pdev)
{
struct iommu_group *group = pdev->dev.iommu_group;
+ struct group_device *gdev;
unsigned long pasid;
void *entry;
int ret;
@@ -3971,33 +4017,52 @@ int pci_dev_reset_iommu_prepare(struct pci_dev *pdev)
guard(mutex)(&group->mutex);
- /* Re-entry is not allowed */
- if (WARN_ON(group->resetting_domain))
- return -EBUSY;
+ gdev = __dev_to_gdev(&pdev->dev);
+ if (WARN_ON(!gdev))
+ return -ENODEV;
+
+ if (gdev->reset_depth++)
+ return 0;
ret = __iommu_group_alloc_blocking_domain(group);
- if (ret)
+ if (ret) {
+ gdev->reset_depth--;
return ret;
+ }
/* Stage RID domain at blocking_domain while retaining group->domain */
if (group->domain != group->blocking_domain) {
ret = __iommu_attach_device(group->blocking_domain, &pdev->dev,
group->domain);
- if (ret)
+ if (ret) {
+ gdev->reset_depth--;
return ret;
+ }
}
+ /*
+ * Update gdev->blocked upon the domain change, as it is used to return
+ * the correct domain in iommu_driver_get_domain_for_dev() that might be
+ * called in a set_dev_pasid callback function.
+ */
+ gdev->blocked = true;
+
/*
* Stage PASID domains at blocking_domain while retaining pasid_array.
*
* The pasid_array is mostly fenced by group->mutex, except one reader
* in iommu_attach_handle_get(), so it's safe to read without xa_lock.
*/
- xa_for_each_start(&group->pasid_array, pasid, entry, 1)
- iommu_remove_dev_pasid(&pdev->dev, pasid,
- pasid_array_entry_to_domain(entry));
+ if (pdev->dev.iommu->max_pasids > 0) {
+ xa_for_each_start(&group->pasid_array, pasid, entry, 1) {
+ struct iommu_domain *pasid_dom =
+ pasid_array_entry_to_domain(entry);
+
+ iommu_remove_dev_pasid(&pdev->dev, pasid, pasid_dom);
+ }
+ }
- group->resetting_domain = group->blocking_domain;
+ group->recovery_cnt++;
return ret;
}
EXPORT_SYMBOL_GPL(pci_dev_reset_iommu_prepare);
@@ -4019,6 +4084,7 @@ EXPORT_SYMBOL_GPL(pci_dev_reset_iommu_prepare);
void pci_dev_reset_iommu_done(struct pci_dev *pdev)
{
struct iommu_group *group = pdev->dev.iommu_group;
+ struct group_device *gdev;
unsigned long pasid;
void *entry;
@@ -4027,32 +4093,56 @@ void pci_dev_reset_iommu_done(struct pci_dev *pdev)
guard(mutex)(&group->mutex);
- /* pci_dev_reset_iommu_prepare() was bypassed for the device */
- if (!group->resetting_domain)
+ gdev = __dev_to_gdev(&pdev->dev);
+ if (WARN_ON(!gdev))
+ return;
+
+ /* Unbalanced done() calls would underflow the counter */
+ if (WARN_ON(gdev->reset_depth == 0))
+ return;
+ if (--gdev->reset_depth)
return;
- /* pci_dev_reset_iommu_prepare() was not successfully called */
if (WARN_ON(!group->blocking_domain))
return;
- /* Re-attach RID domain back to group->domain */
- if (group->domain != group->blocking_domain) {
+ /*
+ * Re-attach RID domain back to group->domain
+ *
+ * Leave the device parked in the blocking_domain if group->domain isn't
+ * initialized yet
+ */
+ if (group->domain && group->domain != group->blocking_domain) {
WARN_ON(__iommu_attach_device(group->domain, &pdev->dev,
group->blocking_domain));
}
+ /*
+ * Update gdev->blocked upon the domain change, as it is used to return
+ * the correct domain in iommu_driver_get_domain_for_dev() that might be
+ * called in a set_dev_pasid callback function.
+ */
+ gdev->blocked = false;
+
/*
* Re-attach PASID domains back to the domains retained in pasid_array.
*
* The pasid_array is mostly fenced by group->mutex, except one reader
* in iommu_attach_handle_get(), so it's safe to read without xa_lock.
*/
- xa_for_each_start(&group->pasid_array, pasid, entry, 1)
- WARN_ON(__iommu_set_group_pasid(
- pasid_array_entry_to_domain(entry), group, pasid,
- group->blocking_domain));
+ if (pdev->dev.iommu->max_pasids > 0) {
+ xa_for_each_start(&group->pasid_array, pasid, entry, 1) {
+ struct iommu_domain *pasid_dom =
+ pasid_array_entry_to_domain(entry);
+
+ WARN_ON(pasid_dom->ops->set_dev_pasid(
+ pasid_dom, &pdev->dev, pasid,
+ group->blocking_domain));
+ }
+ }
- group->resetting_domain = NULL;
+ if (!WARN_ON(group->recovery_cnt == 0))
+ group->recovery_cnt--;
}
EXPORT_SYMBOL_GPL(pci_dev_reset_iommu_done);
diff --git a/drivers/iommu/iommufd/selftest.c b/drivers/iommu/iommufd/selftest.c
index 7823142097d4..83e2215e7800 100644
--- a/drivers/iommu/iommufd/selftest.c
+++ b/drivers/iommu/iommufd/selftest.c
@@ -636,7 +636,7 @@ static void mock_viommu_destroy(struct iommufd_viommu *viommu)
if (mock_viommu->mmap_offset)
iommufd_viommu_destroy_mmap(&mock_viommu->core,
mock_viommu->mmap_offset);
- free_page((unsigned long)mock_viommu->page);
+ free_pages((unsigned long)mock_viommu->page, 1);
mutex_destroy(&mock_viommu->queue_mutex);
/* iommufd core frees mock_viommu and viommu */
@@ -870,7 +870,7 @@ static int mock_viommu_init(struct iommufd_viommu *viommu,
iommufd_viommu_destroy_mmap(&mock_viommu->core,
mock_viommu->mmap_offset);
err_free_page:
- free_page((unsigned long)mock_viommu->page);
+ free_pages((unsigned long)mock_viommu->page, 1);
return rc;
}
diff --git a/drivers/iommu/iommufd/vfio_compat.c b/drivers/iommu/iommufd/vfio_compat.c
index a258ee2f4579..acb48cdd3b00 100644
--- a/drivers/iommu/iommufd/vfio_compat.c
+++ b/drivers/iommu/iommufd/vfio_compat.c
@@ -283,7 +283,7 @@ static int iommufd_vfio_check_extension(struct iommufd_ctx *ictx,
case VFIO_TYPE1_IOMMU:
case VFIO_TYPE1v2_IOMMU:
case VFIO_UNMAP_ALL:
- return 1;
+ return !ictx->no_iommu_mode;
case VFIO_NOIOMMU_IOMMU:
return IS_ENABLED(CONFIG_VFIO_NOIOMMU);
diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig
index c071816f59a6..fb8e217edc3d 100644
--- a/drivers/iommu/riscv/Kconfig
+++ b/drivers/iommu/riscv/Kconfig
@@ -4,6 +4,7 @@
config RISCV_IOMMU
bool "RISC-V IOMMU Support"
depends on RISCV && 64BIT
+ depends on GENERIC_MSI_IRQ
default y
select IOMMU_API
help
diff --git a/drivers/iommu/riscv/iommu-platform.c b/drivers/iommu/riscv/iommu-platform.c
index 83a28c83f991..399ba8fe1b3e 100644
--- a/drivers/iommu/riscv/iommu-platform.c
+++ b/drivers/iommu/riscv/iommu-platform.c
@@ -68,12 +68,7 @@ static int riscv_iommu_platform_probe(struct platform_device *pdev)
iommu->caps = riscv_iommu_readq(iommu, RISCV_IOMMU_REG_CAPABILITIES);
iommu->fctl = riscv_iommu_readl(iommu, RISCV_IOMMU_REG_FCTL);
- iommu->irqs_count = platform_irq_count(pdev);
- if (iommu->irqs_count <= 0)
- return dev_err_probe(dev, -ENODEV,
- "no IRQ resources provided\n");
- if (iommu->irqs_count > RISCV_IOMMU_INTR_COUNT)
- iommu->irqs_count = RISCV_IOMMU_INTR_COUNT;
+ iommu->irqs_count = RISCV_IOMMU_INTR_COUNT;
igs = FIELD_GET(RISCV_IOMMU_CAPABILITIES_IGS, iommu->caps);
switch (igs) {
@@ -120,6 +115,16 @@ static int riscv_iommu_platform_probe(struct platform_device *pdev)
fallthrough;
case RISCV_IOMMU_CAPABILITIES_IGS_WSI:
+ ret = platform_irq_count(pdev);
+ if (ret <= 0)
+ return dev_err_probe(dev, -ENODEV,
+ "no IRQ resources provided\n");
+
+ iommu->irqs_count = ret;
+
+ if (iommu->irqs_count > RISCV_IOMMU_INTR_COUNT)
+ iommu->irqs_count = RISCV_IOMMU_INTR_COUNT;
+
for (vec = 0; vec < iommu->irqs_count; vec++)
iommu->irqs[vec] = platform_get_irq(pdev, vec);
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index fa2ebfd2f912..3ec99c979d47 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -368,6 +368,8 @@ static int riscv_iommu_queue_wait(struct riscv_iommu_queue *queue,
unsigned int timeout_us)
{
unsigned int cons = atomic_read(&queue->head);
+ unsigned int flags = RISCV_IOMMU_CQCSR_CQMF | RISCV_IOMMU_CQCSR_CMD_TO |
+ RISCV_IOMMU_CQCSR_CMD_ILL;
/* Already processed by the consumer */
if ((int)(cons - index) > 0)
@@ -375,6 +377,7 @@ static int riscv_iommu_queue_wait(struct riscv_iommu_queue *queue,
/* Monitor consumer index */
return readx_poll_timeout(riscv_iommu_queue_cons, queue, cons,
+ (riscv_iommu_readl(queue->iommu, queue->qcr) & flags) ||
(int)(cons - index) > 0, 0, timeout_us);
}
@@ -928,8 +931,6 @@ static void riscv_iommu_iotlb_inval(struct riscv_iommu_domain *domain,
struct riscv_iommu_bond *bond;
struct riscv_iommu_device *iommu, *prev;
struct riscv_iommu_command cmd;
- unsigned long len = end - start + 1;
- unsigned long iova;
/*
* For each IOMMU linked with this protection domain (via bonds->dev),
@@ -972,11 +973,14 @@ static void riscv_iommu_iotlb_inval(struct riscv_iommu_domain *domain,
riscv_iommu_cmd_inval_vma(&cmd);
riscv_iommu_cmd_inval_set_pscid(&cmd, domain->pscid);
- if (len && len < RISCV_IOMMU_IOTLB_INVAL_LIMIT) {
- for (iova = start; iova < end; iova += PAGE_SIZE) {
+ if (end - start < RISCV_IOMMU_IOTLB_INVAL_LIMIT - 1) {
+ unsigned long iova = start;
+
+ do {
riscv_iommu_cmd_inval_set_addr(&cmd, iova);
riscv_iommu_cmd_send(iommu, &cmd);
- }
+ } while (!check_add_overflow(iova, PAGE_SIZE, &iova) &&
+ iova < end);
} else {
riscv_iommu_cmd_send(iommu, &cmd);
}
@@ -996,7 +1000,67 @@ static void riscv_iommu_iotlb_inval(struct riscv_iommu_domain *domain,
}
#define RISCV_IOMMU_FSC_BARE 0
+/*
+ * This function sends IOTINVAL commands as required by the RISC-V
+ * IOMMU specification (Section 6.3.1 and 6.3.2 in 1.0 spec version)
+ * after modifying DDT or PDT entries
+ */
+static void riscv_iommu_iodir_iotinval(struct riscv_iommu_device *iommu,
+ bool inval_pdt, unsigned long iohgatp,
+ struct riscv_iommu_dc *dc,
+ struct riscv_iommu_pc *pc)
+{
+ struct riscv_iommu_command cmd;
+ riscv_iommu_cmd_inval_vma(&cmd);
+
+ if (FIELD_GET(RISCV_IOMMU_DC_IOHGATP_MODE, iohgatp) ==
+ RISCV_IOMMU_DC_IOHGATP_MODE_BARE) {
+ if (inval_pdt) {
+ /*
+ * IOTINVAL.VMA with GV=AV=0, and PSCV=1, and
+ * PSCID=PC.PSCID
+ */
+ riscv_iommu_cmd_inval_set_pscid(&cmd,
+ FIELD_GET(RISCV_IOMMU_PC_TA_PSCID, pc->ta));
+ } else {
+ if (!FIELD_GET(RISCV_IOMMU_DC_TC_PDTV, dc->tc) &&
+ FIELD_GET(RISCV_IOMMU_DC_FSC_MODE, dc->fsc) !=
+ RISCV_IOMMU_DC_FSC_MODE_BARE) {
+ /*
+ * DC.tc.PDTV == 0 && DC.fsc.MODE != Bare
+ * IOTINVAL.VMA with GV=AV=0, and PSCV=1, and
+ * PSCID=DC.ta.PSCID
+ */
+ riscv_iommu_cmd_inval_set_pscid(&cmd,
+ FIELD_GET(RISCV_IOMMU_DC_TA_PSCID, dc->ta));
+ }
+ /* else: IOTINVAL.VMA with GV=AV=PSCV=0 */
+ }
+ } else {
+ riscv_iommu_cmd_inval_set_gscid(&cmd,
+ FIELD_GET(RISCV_IOMMU_DC_IOHGATP_GSCID, iohgatp));
+
+ if (inval_pdt) {
+ /*
+ * IOTINVAL.VMA with GV=1, AV=0, and PSCV=1, and
+ * GSCID=DC.iohgatp.GSCID, PSCID=PC.PSCID
+ */
+ riscv_iommu_cmd_inval_set_pscid(&cmd,
+ FIELD_GET(RISCV_IOMMU_PC_TA_PSCID, pc->ta));
+ }
+ /*
+ * else: IOTINVAL.VMA with GV=1,AV=PSCV=0,and
+ * GSCID=DC.iohgatp.GSCID
+ *
+ * IOTINVAL.GVMA with GV=1,AV=0,and
+ * GSCID=DC.iohgatp.GSCID
+ * TODO: For now, the Second-Stage feature have not yet been merged,
+ * also issue IOTINVAL.GVMA once second-stage support is merged.
+ */
+ }
+ riscv_iommu_cmd_send(iommu, &cmd);
+}
/*
* Update IODIR for the device.
*
@@ -1031,6 +1095,11 @@ static void riscv_iommu_iodir_update(struct riscv_iommu_device *iommu,
riscv_iommu_cmd_iodir_inval_ddt(&cmd);
riscv_iommu_cmd_iodir_set_did(&cmd, fwspec->ids[i]);
riscv_iommu_cmd_send(iommu, &cmd);
+ /*
+ * For now, the SVA and PASID features have not yet been merged, the
+ * default configuration is inval_pdt=false and pc=NULL.
+ */
+ riscv_iommu_iodir_iotinval(iommu, false, dc->iohgatp, dc, NULL);
sync_required = true;
}
@@ -1056,6 +1125,11 @@ static void riscv_iommu_iodir_update(struct riscv_iommu_device *iommu,
riscv_iommu_cmd_iodir_inval_ddt(&cmd);
riscv_iommu_cmd_iodir_set_did(&cmd, fwspec->ids[i]);
riscv_iommu_cmd_send(iommu, &cmd);
+ /*
+ * For now, the SVA and PASID features have not yet been merged, the
+ * default configuration is inval_pdt=false and pc=NULL.
+ */
+ riscv_iommu_iodir_iotinval(iommu, false, dc->iohgatp, dc, NULL);
}
riscv_iommu_cmd_sync(iommu, RISCV_IOMMU_IOTINVAL_TIMEOUT);
diff --git a/drivers/irqchip/irq-gic-v5-its.c b/drivers/irqchip/irq-gic-v5-its.c
index 36a8d1368f0e..28e39b065de0 100644
--- a/drivers/irqchip/irq-gic-v5-its.c
+++ b/drivers/irqchip/irq-gic-v5-its.c
@@ -929,14 +929,15 @@ static void gicv5_its_free_eventid(struct gicv5_its_dev *its_dev, u32 event_id_b
static int gicv5_its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs, void *arg)
{
- u32 device_id, event_id_base, lpi;
struct gicv5_its_dev *its_dev;
+ u32 device_id, event_id_base;
msi_alloc_info_t *info = arg;
irq_hw_number_t hwirq;
struct irq_data *irqd;
int ret, i;
its_dev = info->scratchpad[0].ptr;
+ device_id = its_dev->device_id;
ret = gicv5_its_alloc_eventid(its_dev, info, nr_irqs, &event_id_base);
if (ret)
@@ -946,22 +947,11 @@ static int gicv5_its_irq_domain_alloc(struct irq_domain *domain, unsigned int vi
if (ret)
goto out_eventid;
- device_id = its_dev->device_id;
+ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, NULL);
+ if (ret)
+ goto out_eventid;
for (i = 0; i < nr_irqs; i++) {
- ret = gicv5_alloc_lpi();
- if (ret < 0) {
- pr_debug("Failed to find free LPI!\n");
- goto out_free_irqs;
- }
- lpi = ret;
-
- ret = irq_domain_alloc_irqs_parent(domain, virq + i, 1, &lpi);
- if (ret) {
- gicv5_free_lpi(lpi);
- goto out_free_irqs;
- }
-
/*
* Store eventid and deviceid into the hwirq for later use.
*
@@ -980,13 +970,6 @@ static int gicv5_its_irq_domain_alloc(struct irq_domain *domain, unsigned int vi
return 0;
-out_free_irqs:
- while (--i >= 0) {
- irqd = irq_domain_get_irq_data(domain, virq + i);
- gicv5_free_lpi(irqd->parent_data->hwirq);
- irq_domain_reset_irq_data(irqd);
- irq_domain_free_irqs_parent(domain, virq + i, 1);
- }
out_eventid:
gicv5_its_free_eventid(its_dev, event_id_base, nr_irqs);
return ret;
@@ -1009,15 +992,14 @@ static void gicv5_its_irq_domain_free(struct irq_domain *domain, unsigned int vi
bitmap_release_region(its_dev->event_map, event_id_base,
get_count_order(nr_irqs));
- /* Hierarchically free irq data */
for (i = 0; i < nr_irqs; i++) {
d = irq_domain_get_irq_data(domain, virq + i);
-
- gicv5_free_lpi(d->parent_data->hwirq);
irq_domain_reset_irq_data(d);
- irq_domain_free_irqs_parent(domain, virq + i, 1);
}
+ /* Hierarchically free irq data */
+ irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+
gicv5_its_syncr(its, its_dev);
gicv5_irs_syncr();
}
diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c
index 405a5eee847b..386daf5be316 100644
--- a/drivers/irqchip/irq-gic-v5.c
+++ b/drivers/irqchip/irq-gic-v5.c
@@ -59,16 +59,6 @@ static void release_lpi(u32 lpi)
ida_free(&lpi_ida, lpi);
}
-int gicv5_alloc_lpi(void)
-{
- return alloc_lpi();
-}
-
-void gicv5_free_lpi(u32 lpi)
-{
- release_lpi(lpi);
-}
-
static void gicv5_ppi_priority_init(void)
{
write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_PRI_MI), SYS_ICC_PPI_PRIORITYR0_EL1);
@@ -788,38 +778,64 @@ static void gicv5_lpi_config_reset(struct irq_data *d)
gicv5_lpi_irq_write_pending_state(d, false);
}
+static void gicv5_irq_lpi_domain_free(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs)
+{
+ struct irq_data *d;
+
+ for (unsigned int i = 0; i < nr_irqs; i++, virq++) {
+ d = irq_domain_get_irq_data(domain, virq);
+
+ release_lpi(d->hwirq);
+
+ irq_set_handler(virq, NULL);
+ irq_domain_reset_irq_data(d);
+ }
+}
+
static int gicv5_irq_lpi_domain_alloc(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs, void *arg)
{
irq_hw_number_t hwirq;
struct irq_data *irqd;
- u32 *lpi = arg;
+ unsigned int i;
int ret;
- if (WARN_ON_ONCE(nr_irqs != 1))
- return -EINVAL;
+ for (i = 0; i < nr_irqs; i++) {
+ ret = alloc_lpi();
+ if (ret < 0)
+ goto out_free_lpis;
+ hwirq = ret;
+
+ ret = gicv5_irs_iste_alloc(hwirq);
+ if (ret < 0) {
+ /* Undo partial state first, then clean up the rest */
+ release_lpi(hwirq);
+ goto out_free_lpis;
+ }
- hwirq = *lpi;
+ irqd = irq_domain_get_irq_data(domain, virq + i);
- irqd = irq_domain_get_irq_data(domain, virq);
+ irq_domain_set_info(domain, virq + i, hwirq, &gicv5_lpi_irq_chip,
+ NULL, handle_fasteoi_irq, NULL, NULL);
+ irqd_set_single_target(irqd);
- irq_domain_set_info(domain, virq, hwirq, &gicv5_lpi_irq_chip, NULL,
- handle_fasteoi_irq, NULL, NULL);
- irqd_set_single_target(irqd);
+ gicv5_hwirq_init(hwirq, GICV5_IRQ_PRI_MI, GICV5_HWIRQ_TYPE_LPI);
+ gicv5_lpi_config_reset(irqd);
+ }
- ret = gicv5_irs_iste_alloc(hwirq);
- if (ret < 0)
- return ret;
+ return 0;
- gicv5_hwirq_init(hwirq, GICV5_IRQ_PRI_MI, GICV5_HWIRQ_TYPE_LPI);
- gicv5_lpi_config_reset(irqd);
+out_free_lpis:
+ if (i)
+ gicv5_irq_lpi_domain_free(domain, virq, i);
- return 0;
+ return ret;
}
static const struct irq_domain_ops gicv5_irq_lpi_domain_ops = {
.alloc = gicv5_irq_lpi_domain_alloc,
- .free = gicv5_irq_domain_free,
+ .free = gicv5_irq_lpi_domain_free,
};
void __init gicv5_init_lpi_domain(void)
@@ -840,30 +856,21 @@ static int gicv5_irq_ipi_domain_alloc(struct irq_domain *domain, unsigned int vi
unsigned int nr_irqs, void *arg)
{
struct irq_data *irqd;
- int ret, i;
- u32 lpi;
-
- for (i = 0; i < nr_irqs; i++) {
- ret = gicv5_alloc_lpi();
- if (ret < 0)
- return ret;
-
- lpi = ret;
+ int ret;
- ret = irq_domain_alloc_irqs_parent(domain, virq + i, 1, &lpi);
- if (ret) {
- gicv5_free_lpi(lpi);
- return ret;
- }
+ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
+ if (ret)
+ return ret;
- irqd = irq_domain_get_irq_data(domain, virq + i);
+ for (unsigned int i = 0; i < nr_irqs; i++, virq++) {
+ irqd = irq_domain_get_irq_data(domain, virq);
- irq_domain_set_hwirq_and_chip(domain, virq + i, i,
- &gicv5_ipi_irq_chip, NULL);
+ irq_domain_set_hwirq_and_chip(domain, virq, i,
+ &gicv5_ipi_irq_chip, NULL);
irqd_set_single_target(irqd);
- irq_set_handler(virq + i, handle_percpu_irq);
+ irq_set_handler(virq, handle_percpu_irq);
}
return 0;
@@ -881,12 +888,11 @@ static void gicv5_irq_ipi_domain_free(struct irq_domain *domain, unsigned int vi
if (!d)
return;
- gicv5_free_lpi(d->parent_data->hwirq);
-
irq_set_handler(virq + i, NULL);
irq_domain_reset_irq_data(d);
- irq_domain_free_irqs_parent(domain, virq + i, 1);
}
+
+ irq_domain_free_irqs_parent(domain, virq, nr_irqs);
}
static const struct irq_domain_ops gicv5_irq_ipi_domain_ops = {
diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c
index f722e9c57e2e..74a376ef452e 100644
--- a/drivers/irqchip/irq-meson-gpio.c
+++ b/drivers/irqchip/irq-meson-gpio.c
@@ -415,8 +415,7 @@ static int meson_s4_gpio_irq_set_type(struct meson_gpio_irq_controller *ctl,
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
val |= BIT(ctl->params->edge_single_offset + idx);
- meson_gpio_irq_update_bits(ctl, params->edge_pol_reg,
- BIT(idx) | BIT(12 + idx), val);
+ meson_gpio_irq_update_bits(ctl, REG_EDGE_POL, BIT(idx) | BIT(12 + idx), val);
return 0;
};
diff --git a/drivers/irqchip/irq-pic32-evic.c b/drivers/irqchip/irq-pic32-evic.c
index e85c3e300701..325b97a0287f 100644
--- a/drivers/irqchip/irq-pic32-evic.c
+++ b/drivers/irqchip/irq-pic32-evic.c
@@ -196,7 +196,7 @@ static void __init pic32_ext_irq_of_init(struct irq_domain *domain)
of_property_for_each_u32(node, pname, hwirq) {
if (i >= ARRAY_SIZE(priv->ext_irqs)) {
- pr_warn("More than %d external irq, skip rest\n",
+ pr_warn("More than %zu external irq, skip rest\n",
ARRAY_SIZE(priv->ext_irqs));
break;
}
diff --git a/drivers/irqchip/irq-renesas-rzg2l.c b/drivers/irqchip/irq-renesas-rzg2l.c
index e73d426cea6d..eb01d4c5aca7 100644
--- a/drivers/irqchip/irq-renesas-rzg2l.c
+++ b/drivers/irqchip/irq-renesas-rzg2l.c
@@ -577,7 +577,7 @@ static int rzg2l_irqc_common_probe(struct platform_device *pdev, struct device_n
irq_domain = irq_domain_create_hierarchy(parent_domain, 0, IRQC_NUM_IRQ, dev_fwnode(dev),
&rzg2l_irqc_domain_ops, rzg2l_irqc_data);
if (!irq_domain) {
- pm_runtime_put(dev);
+ pm_runtime_put_sync(dev);
return -ENOMEM;
}
diff --git a/drivers/irqchip/irq-riscv-imsic-early.c b/drivers/irqchip/irq-riscv-imsic-early.c
index ba903fa689bd..a7a1852b548c 100644
--- a/drivers/irqchip/irq-riscv-imsic-early.c
+++ b/drivers/irqchip/irq-riscv-imsic-early.c
@@ -158,6 +158,8 @@ static int imsic_dying_cpu(unsigned int cpu)
/* Cleanup IPIs */
imsic_ipi_dying_cpu();
+ imsic_local_sync_all(false);
+
/* Mark per-CPU IMSIC state as offline */
imsic_state_offline();
diff --git a/drivers/leds/blink/leds-lgm-sso.c b/drivers/leds/blink/leds-lgm-sso.c
index 8923d2df4704..3d9ef9a54805 100644
--- a/drivers/leds/blink/leds-lgm-sso.c
+++ b/drivers/leds/blink/leds-lgm-sso.c
@@ -808,8 +808,6 @@ static int intel_sso_led_probe(struct platform_device *pdev)
priv->fpid_clkrate = clk_get_rate(priv->clocks[1].clk);
- priv->mmap = syscon_node_to_regmap(dev->of_node);
-
priv->mmap = syscon_node_to_regmap(dev->of_node);
if (IS_ERR(priv->mmap)) {
dev_err(dev, "Failed to map iomem!\n");
diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c
index 3a28ab5c42e5..41c8c7f3da9d 100644
--- a/drivers/mailbox/mailbox-test.c
+++ b/drivers/mailbox/mailbox-test.c
@@ -28,8 +28,6 @@
#define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \
(MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE))
-static bool mbox_data_ready;
-
struct mbox_test_device {
struct device *dev;
void __iomem *tx_mmio;
@@ -42,6 +40,7 @@ struct mbox_test_device {
spinlock_t lock;
struct mutex mutex;
wait_queue_head_t waitq;
+ bool data_ready;
struct fasync_struct *async_queue;
struct dentry *root_debugfs_dir;
};
@@ -162,7 +161,7 @@ static bool mbox_test_message_data_ready(struct mbox_test_device *tdev)
unsigned long flags;
spin_lock_irqsave(&tdev->lock, flags);
- data_ready = mbox_data_ready;
+ data_ready = tdev->data_ready;
spin_unlock_irqrestore(&tdev->lock, flags);
return data_ready;
@@ -227,7 +226,7 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
*(touser + l) = '\0';
memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN);
- mbox_data_ready = false;
+ tdev->data_ready = false;
spin_unlock_irqrestore(&tdev->lock, flags);
@@ -297,7 +296,7 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message)
message, MBOX_MAX_MSG_LEN);
memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN);
}
- mbox_data_ready = true;
+ tdev->data_ready = true;
spin_unlock_irqrestore(&tdev->lock, flags);
wake_up_interruptible(&tdev->waitq);
@@ -336,7 +335,7 @@ mbox_test_request_channel(struct platform_device *pdev, const char *name)
client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL);
if (!client)
- return ERR_PTR(-ENOMEM);
+ return NULL;
client->dev = &pdev->dev;
client->rx_callback = mbox_test_receive_message;
@@ -366,6 +365,12 @@ static int mbox_test_probe(struct platform_device *pdev)
if (!tdev)
return -ENOMEM;
+ tdev->dev = &pdev->dev;
+ spin_lock_init(&tdev->lock);
+ mutex_init(&tdev->mutex);
+ init_waitqueue_head(&tdev->waitq);
+ platform_set_drvdata(pdev, tdev);
+
/* It's okay for MMIO to be NULL */
tdev->tx_mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (PTR_ERR(tdev->tx_mmio) == -EBUSY) {
@@ -388,34 +393,36 @@ static int mbox_test_probe(struct platform_device *pdev)
tdev->tx_channel = mbox_test_request_channel(pdev, "tx");
tdev->rx_channel = mbox_test_request_channel(pdev, "rx");
- if (IS_ERR_OR_NULL(tdev->tx_channel) && IS_ERR_OR_NULL(tdev->rx_channel))
+ if (!tdev->tx_channel && !tdev->rx_channel)
return -EPROBE_DEFER;
/* If Rx is not specified but has Rx MMIO, then Rx = Tx */
if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio))
tdev->rx_channel = tdev->tx_channel;
- tdev->dev = &pdev->dev;
- platform_set_drvdata(pdev, tdev);
-
- spin_lock_init(&tdev->lock);
- mutex_init(&tdev->mutex);
-
if (tdev->rx_channel) {
tdev->rx_buffer = devm_kzalloc(&pdev->dev,
MBOX_MAX_MSG_LEN, GFP_KERNEL);
- if (!tdev->rx_buffer)
- return -ENOMEM;
+ if (!tdev->rx_buffer) {
+ ret = -ENOMEM;
+ goto err_free_chans;
+ }
}
ret = mbox_test_add_debugfs(pdev, tdev);
if (ret)
- return ret;
+ goto err_free_chans;
- init_waitqueue_head(&tdev->waitq);
dev_info(&pdev->dev, "Successfully registered\n");
return 0;
+
+err_free_chans:
+ if (tdev->tx_channel)
+ mbox_free_channel(tdev->tx_channel);
+ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel)
+ mbox_free_channel(tdev->rx_channel);
+ return ret;
}
static void mbox_test_remove(struct platform_device *pdev)
@@ -426,7 +433,7 @@ static void mbox_test_remove(struct platform_device *pdev)
if (tdev->tx_channel)
mbox_free_channel(tdev->tx_channel);
- if (tdev->rx_channel)
+ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel)
mbox_free_channel(tdev->rx_channel);
}
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index 617ba505691d..b77162db509f 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -505,8 +505,7 @@ int mbox_controller_register(struct mbox_controller *mbox)
{
int i, txdone;
- /* Sanity check */
- if (!mbox || !mbox->dev || !mbox->ops || !mbox->num_chans)
+ if (!mbox || !mbox->dev || !mbox->ops || !mbox->chans || !mbox->num_chans)
return -EINVAL;
if (mbox->txdone_irq)
diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c
index d7c6b38888a3..547a10a8fad3 100644
--- a/drivers/mailbox/mtk-cmdq-mailbox.c
+++ b/drivers/mailbox/mtk-cmdq-mailbox.c
@@ -493,14 +493,14 @@ static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data)
if (curr_pa == end_pa - CMDQ_INST_SIZE ||
curr_pa == end_pa) {
/* set to this task directly */
- writel(task->pa_base >> cmdq->pdata->shift,
- thread->base + CMDQ_THR_CURR_ADDR);
+ gce_addr = cmdq_convert_gce_addr(task->pa_base, cmdq->pdata);
+ writel(gce_addr, thread->base + CMDQ_THR_CURR_ADDR);
} else {
cmdq_task_insert_into_thread(task);
smp_mb(); /* modify jump before enable thread */
}
- writel((task->pa_base + pkt->cmd_buf_size) >> cmdq->pdata->shift,
- thread->base + CMDQ_THR_END_ADDR);
+ gce_addr = cmdq_convert_gce_addr(task->pa_base + pkt->cmd_buf_size, cmdq->pdata);
+ writel(gce_addr, thread->base + CMDQ_THR_END_ADDR);
cmdq_thread_resume(thread);
}
list_move_tail(&task->list_entry, &thread->task_busy_list);
diff --git a/drivers/mailbox/mtk-vcp-mailbox.c b/drivers/mailbox/mtk-vcp-mailbox.c
index cedad575528f..1b291b8ea15a 100644
--- a/drivers/mailbox/mtk-vcp-mailbox.c
+++ b/drivers/mailbox/mtk-vcp-mailbox.c
@@ -50,7 +50,7 @@ static struct mbox_chan *mtk_vcp_mbox_xlate(struct mbox_controller *mbox,
const struct of_phandle_args *sp)
{
if (sp->args_count)
- return NULL;
+ return ERR_PTR(-EINVAL);
return &mbox->chans[0];
}
diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c
index 57158c02d096..ddfc1a3cf2f5 100644
--- a/drivers/md/dm-cache-metadata.c
+++ b/drivers/md/dm-cache-metadata.c
@@ -1023,6 +1023,12 @@ static bool cmd_write_lock(struct dm_cache_metadata *cmd)
return; \
} while (0)
+#define WRITE_LOCK_OR_GOTO(cmd, label) \
+ do { \
+ if (!cmd_write_lock((cmd))) \
+ goto label; \
+ } while (0)
+
#define WRITE_UNLOCK(cmd) \
up_write(&(cmd)->root_lock)
@@ -1714,17 +1720,6 @@ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *
return r;
}
-int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result)
-{
- int r;
-
- READ_LOCK(cmd);
- r = blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result);
- READ_UNLOCK(cmd);
-
- return r;
-}
-
void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd)
{
WRITE_LOCK_VOID(cmd);
@@ -1791,11 +1786,8 @@ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd)
new_bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
CACHE_MAX_CONCURRENT_LOCKS);
- WRITE_LOCK(cmd);
- if (cmd->fail_io) {
- WRITE_UNLOCK(cmd);
- goto out;
- }
+ /* cmd_write_lock() already checks fail_io with cmd->root_lock held */
+ WRITE_LOCK_OR_GOTO(cmd, out);
__destroy_persistent_data_objects(cmd, false);
old_bm = cmd->bm;
diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h
index 5f77890207fe..2f107e7c67d0 100644
--- a/drivers/md/dm-cache-metadata.h
+++ b/drivers/md/dm-cache-metadata.h
@@ -135,11 +135,6 @@ int dm_cache_get_metadata_dev_size(struct dm_cache_metadata *cmd,
*/
int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *p);
-/*
- * Query method. Are all the blocks in the cache clean?
- */
-int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result);
-
int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result);
int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd);
void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd);
diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c
index b328d9601046..dd77a93fd68d 100644
--- a/drivers/md/dm-cache-policy-smq.c
+++ b/drivers/md/dm-cache-policy-smq.c
@@ -1589,14 +1589,18 @@ static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock)
{
struct smq_policy *mq = to_smq_policy(p);
struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock));
+ unsigned long flags;
if (!e->allocated)
return -ENODATA;
+ spin_lock_irqsave(&mq->lock, flags);
// FIXME: what if this block has pending background work?
del_queue(mq, e);
h_remove(&mq->table, e);
free_entry(&mq->cache_alloc, e);
+ spin_unlock_irqrestore(&mq->lock, flags);
+
return 0;
}
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index 935ab79b1d0c..af7a2571988b 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -1462,11 +1462,19 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success)
struct cache *cache = mg->cache;
bio_list_init(&bios);
- if (dm_cell_unlock_v2(cache->prison, mg->cell, &bios))
- free_prison_cell(cache, mg->cell);
+ if (mg->cell) {
+ if (dm_cell_unlock_v2(cache->prison, mg->cell, &bios))
+ free_prison_cell(cache, mg->cell);
+ }
- if (!success && mg->overwrite_bio)
- bio_io_error(mg->overwrite_bio);
+ if (mg->overwrite_bio) {
+ // Set generic error if the bio hasn't been issued yet,
+ // e.g., invalidation or metadata commit failed before bio
+ // submission. Otherwise preserve the bio's own error status.
+ if (!success && !mg->overwrite_bio->bi_status)
+ mg->overwrite_bio->bi_status = BLK_STS_IOERR;
+ bio_endio(mg->overwrite_bio);
+ }
free_migration(mg);
defer_bios(cache, &bios);
@@ -1506,6 +1514,24 @@ static int invalidate_cblock(struct cache *cache, dm_cblock_t cblock)
return r;
}
+static void invalidate_committed(struct work_struct *ws)
+{
+ struct dm_cache_migration *mg = ws_to_mg(ws);
+ struct cache *cache = mg->cache;
+ struct bio *bio = mg->overwrite_bio;
+ struct per_bio_data *pb = get_per_bio_data(bio);
+
+ if (mg->k.input) {
+ invalidate_complete(mg, false);
+ return;
+ }
+
+ init_continuation(&mg->k, invalidate_completed);
+ remap_to_origin_clear_discard(cache, bio, mg->invalidate_oblock);
+ dm_hook_bio(&pb->hook_info, bio, overwrite_endio, mg);
+ dm_submit_bio_remap(bio, NULL);
+}
+
static void invalidate_remove(struct work_struct *ws)
{
int r;
@@ -1518,10 +1544,8 @@ static void invalidate_remove(struct work_struct *ws)
return;
}
- init_continuation(&mg->k, invalidate_completed);
+ init_continuation(&mg->k, invalidate_committed);
continue_after_commit(&cache->committer, &mg->k);
- remap_to_origin_clear_discard(cache, mg->overwrite_bio, mg->invalidate_oblock);
- mg->overwrite_bio = NULL;
schedule_commit(&cache->committer);
}
@@ -1539,6 +1563,15 @@ static int invalidate_lock(struct dm_cache_migration *mg)
READ_WRITE_LOCK_LEVEL, prealloc, &mg->cell);
if (r < 0) {
free_prison_cell(cache, prealloc);
+
+ /* Defer the bio for retrying the cell lock */
+ if (mg->overwrite_bio) {
+ struct bio *bio = mg->overwrite_bio;
+
+ mg->overwrite_bio = NULL;
+ defer_bio(cache, bio);
+ }
+
invalidate_complete(mg, false);
return r;
}
@@ -1701,6 +1734,7 @@ static int map_bio(struct cache *cache, struct bio *bio, dm_oblock_t block,
bio_drop_shared_lock(cache, bio);
atomic_inc(&cache->stats.demotion);
invalidate_start(cache, cblock, block, bio);
+ return DM_MAPIO_SUBMITTED;
} else
remap_to_origin_clear_discard(cache, bio, block);
} else {
@@ -2467,23 +2501,8 @@ static int cache_create(struct cache_args *ca, struct cache **result)
goto bad;
}
- if (passthrough_mode(cache)) {
- bool all_clean;
-
- r = dm_cache_metadata_all_clean(cache->cmd, &all_clean);
- if (r) {
- *error = "dm_cache_metadata_all_clean() failed";
- goto bad;
- }
-
- if (!all_clean) {
- *error = "Cannot enter passthrough mode unless all blocks are clean";
- r = -EINVAL;
- goto bad;
- }
-
+ if (passthrough_mode(cache))
policy_allow_migrations(cache->policy, false);
- }
spin_lock_init(&cache->lock);
bio_list_init(&cache->deferred_bios);
@@ -2810,6 +2829,12 @@ static int load_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock,
struct cache *cache = context;
if (dirty) {
+ if (passthrough_mode(cache)) {
+ DMERR("%s: cannot enter passthrough mode unless all blocks are clean",
+ cache_device_name(cache));
+ return -EBUSY;
+ }
+
set_bit(from_cblock(cblock), cache->dirty_bitset);
atomic_inc(&cache->nr_dirty);
} else
@@ -3043,7 +3068,7 @@ static int cache_preresume(struct dm_target *ti)
load_filtered_mapping, cache);
if (r) {
DMERR("%s: could not load cache mappings", cache_device_name(cache));
- if (r != -EFBIG)
+ if (r != -EFBIG && r != -EBUSY)
metadata_operation_failed(cache, "dm_cache_load_mappings", r);
return r;
}
diff --git a/drivers/md/dm-init.c b/drivers/md/dm-init.c
index 7403823384c5..c1bacba92c65 100644
--- a/drivers/md/dm-init.c
+++ b/drivers/md/dm-init.c
@@ -303,8 +303,10 @@ static int __init dm_init_init(void)
}
}
- if (waitfor[0])
+ if (waitfor[0]) {
+ wait_for_device_probe();
DMINFO("all devices available");
+ }
list_for_each_entry(dev, &devices, list) {
if (dm_early_create(&dev->dmi, dev->table,
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index 1aa6a4a7d232..d316757a328b 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -373,7 +373,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
struct log_c *lc;
uint32_t region_size;
- unsigned int region_count;
+ sector_t region_count;
size_t bitset_size, buf_size;
int r;
char dummy;
@@ -401,6 +401,10 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
}
region_count = dm_sector_div_up(ti->len, region_size);
+ if (region_count > UINT_MAX) {
+ DMWARN("region count exceeds limit of %u", UINT_MAX);
+ return -EINVAL;
+ }
lc = kmalloc_obj(*lc);
if (!lc) {
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 8f4ae2f51545..7cb7bb6233b6 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -102,7 +102,6 @@ struct multipath {
struct bio_list queued_bios;
struct timer_list nopath_timer; /* Timeout for queue_if_no_path */
- bool is_suspending;
};
/*
@@ -1749,9 +1748,6 @@ static void multipath_presuspend(struct dm_target *ti)
{
struct multipath *m = ti->private;
- spin_lock_irq(&m->lock);
- m->is_suspending = true;
- spin_unlock_irq(&m->lock);
/* FIXME: bio-based shouldn't need to always disable queue_if_no_path */
if (m->queue_mode == DM_TYPE_BIO_BASED || !dm_noflush_suspending(m->ti))
queue_if_no_path(m, false, true, __func__);
@@ -1774,7 +1770,6 @@ static void multipath_resume(struct dm_target *ti)
struct multipath *m = ti->private;
spin_lock_irq(&m->lock);
- m->is_suspending = false;
if (test_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &m->flags)) {
set_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags);
clear_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &m->flags);
@@ -2098,7 +2093,7 @@ static int probe_active_paths(struct multipath *m)
if (m->current_pg == m->last_probed_pg)
goto skip_probe;
}
- if (!m->current_pg || m->is_suspending ||
+ if (!m->current_pg || dm_suspended(m->ti) ||
test_bit(MPATHF_QUEUE_IO, &m->flags))
goto skip_probe;
set_bit(MPATHF_DELAY_PG_SWITCH, &m->flags);
@@ -2107,7 +2102,7 @@ static int probe_active_paths(struct multipath *m)
list_for_each_entry(pgpath, &pg->pgpaths, list) {
if (pg != READ_ONCE(m->current_pg) ||
- READ_ONCE(m->is_suspending))
+ dm_suspended(m->ti))
goto out;
if (!pgpath->is_active)
continue;
diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
index 83378c033c72..028b9ca8ce52 100644
--- a/drivers/md/md-bitmap.c
+++ b/drivers/md/md-bitmap.c
@@ -216,6 +216,7 @@ struct bitmap {
};
static struct workqueue_struct *md_bitmap_wq;
+static struct attribute_group md_bitmap_internal_group;
static int __bitmap_resize(struct bitmap *bitmap, sector_t blocks,
int chunksize, bool init);
@@ -2580,6 +2581,30 @@ static int bitmap_resize(struct mddev *mddev, sector_t blocks, int chunksize)
return __bitmap_resize(bitmap, blocks, chunksize, false);
}
+static bool bitmap_none_enabled(void *data, bool flush)
+{
+ return false;
+}
+
+static int bitmap_none_create(struct mddev *mddev)
+{
+ return 0;
+}
+
+static int bitmap_none_load(struct mddev *mddev)
+{
+ return 0;
+}
+
+static void bitmap_none_destroy(struct mddev *mddev)
+{
+}
+
+static int bitmap_none_get_stats(void *data, struct md_bitmap_stats *stats)
+{
+ return -ENOENT;
+}
+
static ssize_t
location_show(struct mddev *mddev, char *page)
{
@@ -2618,7 +2643,11 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
goto out;
}
- bitmap_destroy(mddev);
+ sysfs_unmerge_group(&mddev->kobj, &md_bitmap_internal_group);
+ md_bitmap_destroy_nosysfs(mddev);
+ mddev->bitmap_id = ID_BITMAP_NONE;
+ if (!mddev_set_bitmap_ops_nosysfs(mddev))
+ goto none_err;
mddev->bitmap_info.offset = 0;
if (mddev->bitmap_info.file) {
struct file *f = mddev->bitmap_info.file;
@@ -2654,16 +2683,25 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
}
mddev->bitmap_info.offset = offset;
- rv = bitmap_create(mddev);
+ md_bitmap_destroy_nosysfs(mddev);
+ mddev->bitmap_id = ID_BITMAP;
+ if (!mddev_set_bitmap_ops_nosysfs(mddev))
+ goto bitmap_err;
+
+ rv = md_bitmap_create_nosysfs(mddev);
if (rv)
- goto out;
+ goto create_err;
- rv = bitmap_load(mddev);
+ rv = mddev->bitmap_ops->load(mddev);
if (rv) {
mddev->bitmap_info.offset = 0;
- bitmap_destroy(mddev);
- goto out;
+ goto load_err;
}
+
+ rv = sysfs_merge_group(&mddev->kobj,
+ &md_bitmap_internal_group);
+ if (rv)
+ goto merge_err;
}
}
if (!mddev->external) {
@@ -2679,6 +2717,22 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
if (rv)
return rv;
return len;
+
+merge_err:
+ mddev->bitmap_info.offset = 0;
+load_err:
+ md_bitmap_destroy_nosysfs(mddev);
+create_err:
+ mddev->bitmap_info.offset = 0;
+ mddev->bitmap_id = ID_BITMAP_NONE;
+ if (!mddev_set_bitmap_ops_nosysfs(mddev))
+ rv = -ENOENT;
+ goto out;
+bitmap_err:
+ rv = -ENOENT;
+none_err:
+ mddev->bitmap_info.offset = 0;
+ goto out;
}
static struct md_sysfs_entry bitmap_location =
@@ -2955,8 +3009,12 @@ static struct md_sysfs_entry max_backlog_used =
__ATTR(max_backlog_used, S_IRUGO | S_IWUSR,
behind_writes_used_show, behind_writes_used_reset);
-static struct attribute *md_bitmap_attrs[] = {
+static struct attribute *md_bitmap_common_attrs[] = {
&bitmap_location.attr,
+ NULL
+};
+
+static struct attribute *md_bitmap_internal_attrs[] = {
&bitmap_space.attr,
&bitmap_timeout.attr,
&bitmap_backlog.attr,
@@ -2967,9 +3025,41 @@ static struct attribute *md_bitmap_attrs[] = {
NULL
};
-static struct attribute_group md_bitmap_group = {
+static struct attribute_group md_bitmap_common_group = {
.name = "bitmap",
- .attrs = md_bitmap_attrs,
+ .attrs = md_bitmap_common_attrs,
+};
+
+static struct attribute_group md_bitmap_internal_group = {
+ .name = "bitmap",
+ .attrs = md_bitmap_internal_attrs,
+};
+
+static const struct attribute_group *bitmap_groups[] = {
+ &md_bitmap_common_group,
+ &md_bitmap_internal_group,
+ NULL,
+};
+
+static const struct attribute_group *bitmap_none_groups[] = {
+ &md_bitmap_common_group,
+ NULL,
+};
+
+static struct bitmap_operations bitmap_none_ops = {
+ .head = {
+ .type = MD_BITMAP,
+ .id = ID_BITMAP_NONE,
+ .name = "none",
+ },
+
+ .enabled = bitmap_none_enabled,
+ .create = bitmap_none_create,
+ .load = bitmap_none_load,
+ .destroy = bitmap_none_destroy,
+ .get_stats = bitmap_none_get_stats,
+
+ .groups = bitmap_none_groups,
};
static struct bitmap_operations bitmap_ops = {
@@ -3013,21 +3103,38 @@ static struct bitmap_operations bitmap_ops = {
.set_pages = bitmap_set_pages,
.free = md_bitmap_free,
- .group = &md_bitmap_group,
+ .groups = bitmap_groups,
};
int md_bitmap_init(void)
{
+ int err;
+
md_bitmap_wq = alloc_workqueue("md_bitmap", WQ_MEM_RECLAIM | WQ_UNBOUND,
0);
if (!md_bitmap_wq)
return -ENOMEM;
- return register_md_submodule(&bitmap_ops.head);
+ err = register_md_submodule(&bitmap_none_ops.head);
+ if (err)
+ goto err_wq;
+
+ err = register_md_submodule(&bitmap_ops.head);
+ if (err)
+ goto err_none;
+
+ return 0;
+
+err_none:
+ unregister_md_submodule(&bitmap_none_ops.head);
+err_wq:
+ destroy_workqueue(md_bitmap_wq);
+ return err;
}
void md_bitmap_exit(void)
{
- destroy_workqueue(md_bitmap_wq);
unregister_md_submodule(&bitmap_ops.head);
+ unregister_md_submodule(&bitmap_none_ops.head);
+ destroy_workqueue(md_bitmap_wq);
}
diff --git a/drivers/md/md-bitmap.h b/drivers/md/md-bitmap.h
index b42a28fa83a0..214f623c7e79 100644
--- a/drivers/md/md-bitmap.h
+++ b/drivers/md/md-bitmap.h
@@ -125,7 +125,7 @@ struct bitmap_operations {
void (*set_pages)(void *data, unsigned long pages);
void (*free)(void *data);
- struct attribute_group *group;
+ const struct attribute_group **groups;
};
/* the bitmap API */
diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c
index cdfecaca216b..aeb061166e73 100644
--- a/drivers/md/md-llbitmap.c
+++ b/drivers/md/md-llbitmap.c
@@ -1562,6 +1562,11 @@ static struct attribute_group md_llbitmap_group = {
.attrs = md_llbitmap_attrs,
};
+static const struct attribute_group *md_llbitmap_groups[] = {
+ &md_llbitmap_group,
+ NULL,
+};
+
static struct bitmap_operations llbitmap_ops = {
.head = {
.type = MD_BITMAP,
@@ -1598,7 +1603,7 @@ static struct bitmap_operations llbitmap_ops = {
.dirty_bits = llbitmap_dirty_bits,
.write_all = llbitmap_write_all,
- .group = &md_llbitmap_group,
+ .groups = md_llbitmap_groups,
};
int md_llbitmap_init(void)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 3ce6f9e9d38e..32927c24ebf7 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -84,7 +84,6 @@ static DEFINE_XARRAY(md_submodule);
static const struct kobj_type md_ktype;
static DECLARE_WAIT_QUEUE_HEAD(resync_wait);
-static struct workqueue_struct *md_wq;
/*
* This workqueue is used for sync_work to register new sync_thread, and for
@@ -489,6 +488,17 @@ int mddev_suspend(struct mddev *mddev, bool interruptible)
}
percpu_ref_kill(&mddev->active_io);
+
+ /*
+ * RAID456 IO can sleep in wait_for_reshape while still holding an
+ * active_io reference. If reshape is already interrupted or frozen,
+ * wake those waiters so they can abort and drop the reference instead
+ * of deadlocking suspend.
+ */
+ if (mddev->pers && mddev->pers->prepare_suspend &&
+ reshape_interrupted(mddev))
+ mddev->pers->prepare_suspend(mddev);
+
if (interruptible)
err = wait_event_interruptible(mddev->sb_wait,
percpu_ref_is_zero(&mddev->active_io));
@@ -678,13 +688,38 @@ static void active_io_release(struct percpu_ref *ref)
static void no_op(struct percpu_ref *r) {}
-static bool mddev_set_bitmap_ops(struct mddev *mddev)
+static void md_bitmap_sysfs_add(struct mddev *mddev)
+{
+ if (sysfs_update_groups(&mddev->kobj, mddev->bitmap_ops->groups))
+ pr_warn("md: cannot register extra bitmap attributes for %s\n",
+ mdname(mddev));
+ else
+ /*
+ * Inform user with KOBJ_CHANGE about new bitmap
+ * attributes.
+ */
+ kobject_uevent(&mddev->kobj, KOBJ_CHANGE);
+}
+
+static void md_bitmap_sysfs_del(struct mddev *mddev)
+{
+ int nr_groups = 0;
+
+ for (nr_groups = 0; mddev->bitmap_ops->groups[nr_groups]; nr_groups++)
+ ;
+
+ while (--nr_groups >= 1)
+ sysfs_unmerge_group(&mddev->kobj,
+ mddev->bitmap_ops->groups[nr_groups]);
+ sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->groups[0]);
+}
+
+bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev)
{
- struct bitmap_operations *old = mddev->bitmap_ops;
struct md_submodule_head *head;
- if (mddev->bitmap_id == ID_BITMAP_NONE ||
- (old && old->head.id == mddev->bitmap_id))
+ if (mddev->bitmap_ops &&
+ mddev->bitmap_ops->head.id == mddev->bitmap_id)
return true;
xa_lock(&md_submodule);
@@ -702,18 +737,6 @@ static bool mddev_set_bitmap_ops(struct mddev *mddev)
mddev->bitmap_ops = (void *)head;
xa_unlock(&md_submodule);
-
- if (!mddev_is_dm(mddev) && mddev->bitmap_ops->group) {
- if (sysfs_create_group(&mddev->kobj, mddev->bitmap_ops->group))
- pr_warn("md: cannot register extra bitmap attributes for %s\n",
- mdname(mddev));
- else
- /*
- * Inform user with KOBJ_CHANGE about new bitmap
- * attributes.
- */
- kobject_uevent(&mddev->kobj, KOBJ_CHANGE);
- }
return true;
err:
@@ -721,15 +744,6 @@ static bool mddev_set_bitmap_ops(struct mddev *mddev)
return false;
}
-static void mddev_clear_bitmap_ops(struct mddev *mddev)
-{
- if (!mddev_is_dm(mddev) && mddev->bitmap_ops &&
- mddev->bitmap_ops->group)
- sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->group);
-
- mddev->bitmap_ops = NULL;
-}
-
int mddev_init(struct mddev *mddev)
{
int err = 0;
@@ -2788,7 +2802,9 @@ void md_update_sb(struct mddev *mddev, int force_change)
if (!md_is_rdwr(mddev)) {
if (force_change)
set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags);
- pr_err("%s: can't update sb for read-only array %s\n", __func__, mdname(mddev));
+ if (!mddev_is_dm(mddev))
+ pr_err_ratelimited("%s: can't update sb for read-only array %s\n",
+ __func__, mdname(mddev));
return;
}
@@ -4268,7 +4284,7 @@ bitmap_type_show(struct mddev *mddev, char *page)
xa_lock(&md_submodule);
xa_for_each(&md_submodule, i, head) {
- if (head->type != MD_BITMAP)
+ if (head->type != MD_BITMAP || head->id == ID_BITMAP_NONE)
continue;
if (mddev->bitmap_id == head->id)
@@ -6128,10 +6144,16 @@ md_attr_store(struct kobject *kobj, struct attribute *attr,
}
spin_unlock(&all_mddevs_lock);
rv = entry->store(mddev, page, length);
- mddev_put(mddev);
+ /*
+ * For "array_state=clear", dropping the extra kobject reference from
+ * sysfs_break_active_protection() can trigger md kobject deletion.
+ * Restore active protection before mddev_put() so deletion happens
+ * after the sysfs write path fully unwinds.
+ */
if (kn)
sysfs_unbreak_active_protection(kn);
+ mddev_put(mddev);
return rv;
}
@@ -6447,24 +6469,170 @@ static void md_safemode_timeout(struct timer_list *t)
static int start_dirty_degraded;
-static int md_bitmap_create(struct mddev *mddev)
+/*
+ * Read bitmap superblock and return the bitmap_id based on disk version.
+ * This is used as fallback when default bitmap version and on-disk version
+ * doesn't match, and mdadm is not the latest version to set bitmap_type.
+ */
+static enum md_submodule_id md_bitmap_get_id_from_sb(struct mddev *mddev)
{
+ struct md_rdev *rdev;
+ struct page *sb_page;
+ bitmap_super_t *sb;
+ enum md_submodule_id id = ID_BITMAP_NONE;
+ sector_t sector;
+ u32 version;
+
+ if (!mddev->bitmap_info.offset)
+ return ID_BITMAP_NONE;
+
+ sb_page = alloc_page(GFP_KERNEL);
+ if (!sb_page) {
+ pr_warn("md: %s: failed to allocate memory for bitmap\n",
+ mdname(mddev));
+ return ID_BITMAP_NONE;
+ }
+
+ sector = mddev->bitmap_info.offset;
+
+ rdev_for_each(rdev, mddev) {
+ u32 iosize;
+
+ if (!test_bit(In_sync, &rdev->flags) ||
+ test_bit(Faulty, &rdev->flags) ||
+ test_bit(Bitmap_sync, &rdev->flags))
+ continue;
+
+ iosize = roundup(sizeof(bitmap_super_t),
+ bdev_logical_block_size(rdev->bdev));
+ if (sync_page_io(rdev, sector, iosize, sb_page, REQ_OP_READ,
+ true))
+ goto read_ok;
+ }
+ pr_warn("md: %s: failed to read bitmap from any device\n",
+ mdname(mddev));
+ goto out;
+
+read_ok:
+ sb = kmap_local_page(sb_page);
+ if (sb->magic != cpu_to_le32(BITMAP_MAGIC)) {
+ pr_warn("md: %s: invalid bitmap magic 0x%x\n",
+ mdname(mddev), le32_to_cpu(sb->magic));
+ goto out_unmap;
+ }
+
+ version = le32_to_cpu(sb->version);
+ switch (version) {
+ case BITMAP_MAJOR_LO:
+ case BITMAP_MAJOR_HI:
+ case BITMAP_MAJOR_CLUSTERED:
+ id = ID_BITMAP;
+ break;
+ case BITMAP_MAJOR_LOCKLESS:
+ id = ID_LLBITMAP;
+ break;
+ default:
+ pr_warn("md: %s: unknown bitmap version %u\n",
+ mdname(mddev), version);
+ break;
+ }
+
+out_unmap:
+ kunmap_local(sb);
+out:
+ __free_page(sb_page);
+ return id;
+}
+
+int md_bitmap_create_nosysfs(struct mddev *mddev)
+{
+ enum md_submodule_id orig_id = mddev->bitmap_id;
+ enum md_submodule_id sb_id;
+ int err;
+
if (mddev->bitmap_id == ID_BITMAP_NONE)
return -EINVAL;
- if (!mddev_set_bitmap_ops(mddev))
+ if (!mddev_set_bitmap_ops_nosysfs(mddev)) {
+ mddev->bitmap_id = orig_id;
return -ENOENT;
+ }
+
+ err = mddev->bitmap_ops->create(mddev);
+ if (!err)
+ return 0;
- return mddev->bitmap_ops->create(mddev);
+ /*
+ * Create failed, if default bitmap version and on-disk version
+ * doesn't match, and mdadm is not the latest version to set
+ * bitmap_type, set bitmap_ops based on the disk version.
+ */
+ mddev->bitmap_ops = NULL;
+
+ sb_id = md_bitmap_get_id_from_sb(mddev);
+ if (sb_id == ID_BITMAP_NONE || sb_id == orig_id) {
+ mddev->bitmap_id = orig_id;
+ return err;
+ }
+
+ pr_info("md: %s: bitmap version mismatch, switching from %d to %d\n",
+ mdname(mddev), orig_id, sb_id);
+
+ mddev->bitmap_id = sb_id;
+ if (!mddev_set_bitmap_ops_nosysfs(mddev)) {
+ mddev->bitmap_id = orig_id;
+ return -ENOENT;
+ }
+
+ err = mddev->bitmap_ops->create(mddev);
+ if (err) {
+ mddev->bitmap_ops = NULL;
+ mddev->bitmap_id = orig_id;
+ }
+
+ return err;
}
-static void md_bitmap_destroy(struct mddev *mddev)
+static int md_bitmap_create(struct mddev *mddev)
+{
+ int err;
+
+ err = md_bitmap_create_nosysfs(mddev);
+ if (err)
+ return err;
+
+ if (!mddev_is_dm(mddev) && mddev->bitmap_ops->groups)
+ md_bitmap_sysfs_add(mddev);
+
+ return 0;
+}
+
+void md_bitmap_destroy_nosysfs(struct mddev *mddev)
{
if (!md_bitmap_registered(mddev))
return;
mddev->bitmap_ops->destroy(mddev);
- mddev_clear_bitmap_ops(mddev);
+ mddev->bitmap_ops = NULL;
+}
+
+static void md_bitmap_destroy(struct mddev *mddev)
+{
+ if (!mddev_is_dm(mddev) && mddev->bitmap_ops &&
+ mddev->bitmap_ops->groups)
+ md_bitmap_sysfs_del(mddev);
+
+ md_bitmap_destroy_nosysfs(mddev);
+}
+
+static void md_bitmap_set_none(struct mddev *mddev)
+{
+ mddev->bitmap_id = ID_BITMAP_NONE;
+ if (!mddev_set_bitmap_ops_nosysfs(mddev))
+ return;
+
+ if (!mddev_is_dm(mddev) && mddev->bitmap_ops->groups)
+ md_bitmap_sysfs_add(mddev);
}
int md_run(struct mddev *mddev)
@@ -6676,6 +6844,10 @@ int md_run(struct mddev *mddev)
if (mddev->sb_flags)
md_update_sb(mddev, 0);
+ if (IS_ENABLED(CONFIG_MD_BITMAP) && !mddev->bitmap_info.file &&
+ !mddev->bitmap_info.offset)
+ md_bitmap_set_none(mddev);
+
md_new_event();
return 0;
@@ -7621,7 +7793,8 @@ static int set_bitmap_file(struct mddev *mddev, int fd)
{
int err = 0;
- if (!md_bitmap_registered(mddev))
+ if (!md_bitmap_registered(mddev) ||
+ mddev->bitmap_id == ID_BITMAP_NONE)
return -EINVAL;
if (mddev->pers) {
@@ -7686,10 +7859,12 @@ static int set_bitmap_file(struct mddev *mddev, int fd)
if (err) {
md_bitmap_destroy(mddev);
+ md_bitmap_set_none(mddev);
fd = -1;
}
} else if (fd < 0) {
md_bitmap_destroy(mddev);
+ md_bitmap_set_none(mddev);
}
}
@@ -7996,12 +8171,16 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
mddev->bitmap_info.default_offset;
mddev->bitmap_info.space =
mddev->bitmap_info.default_space;
+ mddev->bitmap_id = ID_BITMAP;
rv = md_bitmap_create(mddev);
if (!rv)
rv = mddev->bitmap_ops->load(mddev);
- if (rv)
+ if (rv) {
md_bitmap_destroy(mddev);
+ mddev->bitmap_info.offset = 0;
+ md_bitmap_set_none(mddev);
+ }
} else {
struct md_bitmap_stats stats;
@@ -8029,6 +8208,7 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
}
md_bitmap_destroy(mddev);
mddev->bitmap_info.offset = 0;
+ md_bitmap_set_none(mddev);
}
}
md_update_sb(mddev, 1);
@@ -10503,10 +10683,6 @@ static int __init md_init(void)
goto err_bitmap;
ret = -ENOMEM;
- md_wq = alloc_workqueue("md", WQ_MEM_RECLAIM | WQ_PERCPU, 0);
- if (!md_wq)
- goto err_wq;
-
md_misc_wq = alloc_workqueue("md_misc", WQ_PERCPU, 0);
if (!md_misc_wq)
goto err_misc_wq;
@@ -10531,8 +10707,6 @@ static int __init md_init(void)
err_md:
destroy_workqueue(md_misc_wq);
err_misc_wq:
- destroy_workqueue(md_wq);
-err_wq:
md_llbitmap_exit();
err_bitmap:
md_bitmap_exit();
@@ -10841,7 +11015,6 @@ static __exit void md_exit(void)
spin_unlock(&all_mddevs_lock);
destroy_workqueue(md_misc_wq);
- destroy_workqueue(md_wq);
md_bitmap_exit();
}
diff --git a/drivers/md/md.h b/drivers/md/md.h
index ac84289664cd..409c8f61695d 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -932,6 +932,9 @@ extern void md_allow_write(struct mddev *mddev);
extern void md_wait_for_blocked_rdev(struct md_rdev *rdev, struct mddev *mddev);
extern void md_set_array_sectors(struct mddev *mddev, sector_t array_sectors);
extern int md_check_no_bitmap(struct mddev *mddev);
+bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev);
+int md_bitmap_create_nosysfs(struct mddev *mddev);
+void md_bitmap_destroy_nosysfs(struct mddev *mddev);
extern int md_integrity_register(struct mddev *mddev);
extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale);
diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c
index c33099925f23..56a56a4da4f8 100644
--- a/drivers/md/raid1-10.c
+++ b/drivers/md/raid1-10.c
@@ -293,8 +293,13 @@ static inline bool raid1_should_read_first(struct mddev *mddev,
* bio with REQ_RAHEAD or REQ_NOWAIT can fail at anytime, before such IO is
* submitted to the underlying disks, hence don't record badblocks or retry
* in this case.
+ *
+ * BLK_STS_INVAL means the bio was not valid for the underlying device. This
+ * is a user error, not a device failure, so retrying or recording bad blocks
+ * would be wrong.
*/
static inline bool raid1_should_handle_error(struct bio *bio)
{
- return !(bio->bi_opf & (REQ_RAHEAD | REQ_NOWAIT));
+ return !(bio->bi_opf & (REQ_RAHEAD | REQ_NOWAIT)) &&
+ bio->bi_status != BLK_STS_INVAL;
}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 181400e147c0..be2565dee420 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -62,7 +62,7 @@ static int check_and_add_serial(struct md_rdev *rdev, struct r1bio *r1_bio,
unsigned long flags;
int ret = 0;
sector_t lo = r1_bio->sector;
- sector_t hi = lo + r1_bio->sectors;
+ sector_t hi = lo + r1_bio->sectors - 1;
struct serial_in_rdev *serial = &rdev->serial[idx];
spin_lock_irqsave(&serial->serial_lock, flags);
@@ -452,7 +452,7 @@ static void raid1_end_write_request(struct bio *bio)
int mirror = find_bio_disk(r1_bio, bio);
struct md_rdev *rdev = conf->mirrors[mirror].rdev;
sector_t lo = r1_bio->sector;
- sector_t hi = r1_bio->sector + r1_bio->sectors;
+ sector_t hi = r1_bio->sector + r1_bio->sectors - 1;
bool ignore_error = !raid1_should_handle_error(bio) ||
(bio->bi_status && bio_op(bio) == REQ_OP_DISCARD);
diff --git a/drivers/media/i2c/og01a1b.c b/drivers/media/i2c/og01a1b.c
index c7184de6251a..7b892b26203c 100644
--- a/drivers/media/i2c/og01a1b.c
+++ b/drivers/media/i2c/og01a1b.c
@@ -1042,6 +1042,7 @@ static void og01a1b_remove(struct i2c_client *client)
struct og01a1b *og01a1b = to_og01a1b(sd);
v4l2_async_unregister_subdev(sd);
+ v4l2_subdev_cleanup(&og01a1b->sd);
media_entity_cleanup(&sd->entity);
v4l2_ctrl_handler_free(sd->ctrl_handler);
pm_runtime_disable(og01a1b->dev);
@@ -1153,11 +1154,18 @@ static int og01a1b_probe(struct i2c_client *client)
goto probe_error_v4l2_ctrl_handler_free;
}
+ ret = v4l2_subdev_init_finalize(&og01a1b->sd);
+ if (ret < 0) {
+ dev_err_probe(og01a1b->dev, ret,
+ "failed to finalize subdevice init\n");
+ goto probe_error_media_entity_cleanup;
+ }
+
ret = v4l2_async_register_subdev_sensor(&og01a1b->sd);
if (ret < 0) {
dev_err(og01a1b->dev, "failed to register V4L2 subdev: %d",
ret);
- goto probe_error_media_entity_cleanup;
+ goto probe_error_v4l2_subdev_cleanup;
}
/* Enable runtime PM and turn off the device */
@@ -1167,6 +1175,9 @@ static int og01a1b_probe(struct i2c_client *client)
return 0;
+probe_error_v4l2_subdev_cleanup:
+ v4l2_subdev_cleanup(&og01a1b->sd);
+
probe_error_media_entity_cleanup:
media_entity_cleanup(&og01a1b->sd.entity);
diff --git a/drivers/media/platform/synopsys/Kconfig b/drivers/media/platform/synopsys/Kconfig
index bf2ac092fbb3..b109de2c8111 100644
--- a/drivers/media/platform/synopsys/Kconfig
+++ b/drivers/media/platform/synopsys/Kconfig
@@ -4,6 +4,7 @@ source "drivers/media/platform/synopsys/hdmirx/Kconfig"
config VIDEO_DW_MIPI_CSI2RX
tristate "Synopsys DesignWare MIPI CSI-2 Receiver"
+ depends on ARCH_ROCKCHIP || COMPILE_TEST
depends on VIDEO_DEV
depends on V4L_PLATFORM_DRIVERS
depends on PM && COMMON_CLK
diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c
index ff26815e51f1..5cfbc169c5f9 100644
--- a/drivers/memory/tegra/tegra124-emc.c
+++ b/drivers/memory/tegra/tegra124-emc.c
@@ -608,7 +608,7 @@ static int tegra124_emc_prepare_timing_change(struct tegra_emc *emc,
if ((last->emc_mode_1 & 0x1) == (timing->emc_mode_1 & 0x1))
dll_change = DLL_CHANGE_NONE;
- else if (timing->emc_mode_1 & 0x1)
+ else if (!(timing->emc_mode_1 & 0x1))
dll_change = DLL_CHANGE_ON;
else
dll_change = DLL_CHANGE_OFF;
diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c
index 606106dd2b32..5812c8cd6ce4 100644
--- a/drivers/memory/tegra/tegra30-emc.c
+++ b/drivers/memory/tegra/tegra30-emc.c
@@ -554,14 +554,14 @@ static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate)
emc->emc_cfg = readl_relaxed(emc->regs + EMC_CFG);
emc_dbg = readl_relaxed(emc->regs + EMC_DBG);
- if (emc->dll_on == !!(timing->emc_mode_1 & 0x1))
+ if (emc->dll_on == !(timing->emc_mode_1 & 0x1))
dll_change = DLL_CHANGE_NONE;
- else if (timing->emc_mode_1 & 0x1)
+ else if (!(timing->emc_mode_1 & 0x1))
dll_change = DLL_CHANGE_ON;
else
dll_change = DLL_CHANGE_OFF;
- emc->dll_on = !!(timing->emc_mode_1 & 0x1);
+ emc->dll_on = !(timing->emc_mode_1 & 0x1);
if (timing->data[80] && !readl_relaxed(emc->regs + EMC_ZCAL_INTERVAL))
emc->zcal_long = true;
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index 920797b806ce..786eab3b2d03 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -377,7 +377,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
if (snprintf(buf, sizeof(buf), format, name) > sizeof(buf))
return -E2BIG;
- cell.name = kmemdup(buf, strlen(buf) + 1, GFP_KERNEL);
+ cell.name = devm_kmemdup(mc13xxx->dev, buf, strlen(buf) + 1, GFP_KERNEL);
if (!cell.name)
return -ENOMEM;
diff --git a/drivers/mtd/maps/physmap-gemini.c b/drivers/mtd/maps/physmap-gemini.c
index 9d3b4bf84a1a..1c34b4ef77ea 100644
--- a/drivers/mtd/maps/physmap-gemini.c
+++ b/drivers/mtd/maps/physmap-gemini.c
@@ -181,7 +181,7 @@ int of_flash_probe_gemini(struct platform_device *pdev,
dev_err(dev, "no enabled pin control state\n");
gf->disabled_state = pinctrl_lookup_state(gf->p, "disabled");
- if (IS_ERR(gf->enabled_state)) {
+ if (IS_ERR(gf->disabled_state)) {
dev_err(dev, "no disabled pin control state\n");
} else {
ret = pinctrl_select_state(gf->p, gf->disabled_state);
diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
index e66adfcca7cd..85b869041a37 100644
--- a/drivers/mtd/nand/raw/sunxi_nand.c
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -1048,9 +1048,9 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct nand_chip *nand,
if (len <= 0)
return;
- if (!cur_off || *cur_off != offset)
- nand_change_read_column_op(nand, mtd->writesize, NULL, 0,
- false);
+ if (!cur_off || *cur_off != (offset + mtd->writesize))
+ nand_change_read_column_op(nand, mtd->writesize + offset,
+ NULL, 0, false);
if (!randomize)
sunxi_nfc_read_buf(nand, oob + offset, len);
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 8aa3753aaaa1..0b076790bd9d 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -100,6 +100,17 @@ spinand_fill_page_read_op(struct spinand_device *spinand, u64 addr)
return op;
}
+static struct spi_mem_op
+spinand_fill_page_read_packed_op(struct spinand_device *spinand, u64 addr)
+{
+ struct spi_mem_op op = spinand->op_templates->page_read;
+
+ op.cmd.opcode |= addr >> 16;
+ op.addr.val = addr & 0xFFFF;
+
+ return op;
+}
+
struct spi_mem_op
spinand_fill_prog_exec_op(struct spinand_device *spinand, u64 addr)
{
@@ -453,7 +464,10 @@ static int spinand_load_page_op(struct spinand_device *spinand,
{
struct nand_device *nand = spinand_to_nand(spinand);
unsigned int row = nanddev_pos_to_row(nand, &req->pos);
- struct spi_mem_op op = SPINAND_OP(spinand, page_read, row);
+ bool packed = spinand->flags & SPINAND_ODTR_PACKED_PAGE_READ;
+ struct spi_mem_op op = packed ?
+ SPINAND_OP(spinand, page_read_packed, row) :
+ SPINAND_OP(spinand, page_read, row);
return spi_mem_exec_op(spinand->spimem, &op);
}
@@ -1489,9 +1503,13 @@ static int spinand_init_odtr_instruction_set(struct spinand_device *spinand)
if (!spi_mem_supports_op(spinand->spimem, &tmpl->blk_erase))
return -EOPNOTSUPP;
- tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_8D_8D_0_OP(0);
- if (!spi_mem_supports_op(spinand->spimem, &tmpl->page_read))
+ if (spinand->flags & SPINAND_ODTR_PACKED_PAGE_READ)
+ tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_PACKED_8D_8D_0_OP(0);
+ else
+ tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_8D_8D_0_OP(0);
+ if (!spi_mem_supports_op(spinand->spimem, &tmpl->page_read)) {
return -EOPNOTSUPP;
+ }
tmpl->prog_exec = (struct spi_mem_op)SPINAND_PROG_EXEC_8D_8D_0_OP(0);
if (!spi_mem_supports_op(spinand->spimem, &tmpl->prog_exec))
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 4f9f1854e0cf..7cc0f0091430 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -99,7 +99,7 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
#define SPINAND_WINBOND_WRITE_VCR_8D_8D_8D(reg, buf) \
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x81, 8), \
- SPI_MEM_DTR_OP_ADDR(4, reg, 8), \
+ SPI_MEM_DTR_OP_ADDR(4, reg << 8, 8), \
SPI_MEM_OP_NO_DUMMY, \
SPI_MEM_DTR_OP_DATA_OUT(2, buf, 8))
@@ -337,16 +337,19 @@ static int w25n0xjw_hs_cfg(struct spinand_device *spinand,
if (iface != SSDR)
return -EOPNOTSUPP;
+ /*
+ * SDR dual and quad I/O operations over 104MHz require the HS bit to
+ * enable a few more dummy cycles.
+ */
op = spinand->op_templates->read_cache;
if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
hs = false;
- else if (op->cmd.buswidth == 1 && op->addr.buswidth == 1 &&
- op->dummy.buswidth == 1 && op->data.buswidth == 1)
+ else if (op->cmd.buswidth != 1 || op->addr.buswidth == 1)
hs = false;
- else if (!op->max_freq)
- hs = true;
- else
+ else if (op->max_freq && op->max_freq <= 104 * HZ_PER_MHZ)
hs = false;
+ else
+ hs = true;
ret = spinand_read_reg_op(spinand, W25N0XJW_SR4, &sr4);
if (ret)
@@ -515,7 +518,7 @@ static const struct spinand_info winbond_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants,
&write_cache_octal_variants,
&update_cache_octal_variants),
- 0,
+ SPINAND_ODTR_PACKED_PAGE_READ,
SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops),
SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
@@ -526,7 +529,7 @@ static const struct spinand_info winbond_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants,
&write_cache_octal_variants,
&update_cache_octal_variants),
- 0,
+ SPINAND_ODTR_PACKED_PAGE_READ,
SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops),
SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c
index 0029bda165bd..262c4221d23f 100644
--- a/drivers/mtd/parsers/ofpart_core.c
+++ b/drivers/mtd/parsers/ofpart_core.c
@@ -75,7 +75,7 @@ static int parse_fixed_partitions(struct mtd_info *master,
dedicated = false;
}
} else { /* Partition */
- ofpart_node = mtd_node;
+ ofpart_node = of_node_get(mtd_node);
}
of_id = of_match_node(parse_ofpart_match_table, ofpart_node);
@@ -195,11 +195,11 @@ static int parse_fixed_partitions(struct mtd_info *master,
ofpart_fail:
pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n",
master->name, pp, mtd_node);
+ of_node_put(pp);
ret = -EINVAL;
ofpart_none:
if (dedicated)
of_node_put(ofpart_node);
- of_node_put(pp);
kfree(parts);
return ret;
}
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 1eee519c01e5..5dd0b3cb5250 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -2393,7 +2393,7 @@ static int spi_nor_spimem_check_readop(struct spi_nor *nor,
/* convert the dummy cycles to the number of bytes */
op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) *
op.dummy.buswidth / 8;
- if (spi_nor_protocol_is_dtr(nor->read_proto))
+ if (spi_nor_protocol_is_dtr(read->proto))
op.dummy.nbytes *= 2;
return spi_nor_spimem_check_read_pp_op(nor, &op);
diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h
index 16b382d4f04f..e838c40a2589 100644
--- a/drivers/mtd/spi-nor/core.h
+++ b/drivers/mtd/spi-nor/core.h
@@ -413,7 +413,7 @@ struct spi_nor_flash_parameter {
* number of dummy cycles in read register ops.
* @smpt_map_id: called after map ID in SMPT table has been determined for the
* case the map ID is wrong and needs to be fixed.
- * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs
+ * @post_sfdp: called after SFDP has been parsed (is not called for SPI NORs
* that do not support RDSFDP). Typically used to tweak various
* parameters that could not be extracted by other means (i.e.
* when information provided by the SFDP/flash_info tables are
diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c
index 88033384a71e..b2b473501d02 100644
--- a/drivers/mtd/spi-nor/micron-st.c
+++ b/drivers/mtd/spi-nor/micron-st.c
@@ -167,6 +167,16 @@ static int mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor)
0, 20, SPINOR_OP_MT_DTR_RD,
SNOR_PROTO_8_8_8_DTR);
+ /*
+ * Some batches of mt35xu512aba do not contain the OCT DTR command
+ * information, but do support OCT DTR mode. Add the settings for
+ * SNOR_CMD_PP_8_8_8_DTR here. This also makes sure the flash can switch
+ * to OCT DTR mode.
+ */
+ nor->params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR;
+ spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP_8_8_8_DTR],
+ SPINOR_OP_PP_4B, SNOR_PROTO_8_8_8_DTR);
+
nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
nor->params->rdsr_dummy = 8;
nor->params->rdsr_addr_nbytes = 0;
diff --git a/drivers/mtd/spi-nor/swp.c b/drivers/mtd/spi-nor/swp.c
index 9b07f83aeac7..e67a81dbb6bf 100644
--- a/drivers/mtd/spi-nor/swp.c
+++ b/drivers/mtd/spi-nor/swp.c
@@ -28,8 +28,10 @@ static u8 spi_nor_get_sr_tb_mask(struct spi_nor *nor)
{
if (nor->flags & SNOR_F_HAS_SR_TB_BIT6)
return SR_TB_BIT6;
- else
+ else if (nor->flags & SNOR_F_HAS_SR_TB)
return SR_TB_BIT5;
+ else
+ return 0;
}
static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor)
diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c
index 0df3208783ad..da5866ba0699 100644
--- a/drivers/net/bareudp.c
+++ b/drivers/net/bareudp.c
@@ -529,6 +529,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev,
struct in6_addr saddr;
struct socket *sock = rcu_dereference(bareudp->sock);
+ if (!sock)
+ return -ESHUTDOWN;
+
dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock,
0, &saddr, &info->key,
sport, bareudp->port, info->key.tos,
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index af7f74cfdc08..f0aa7d2f2171 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -1029,6 +1029,7 @@ static void ad_cond_set_peer_notif(struct port *port)
static void ad_mux_machine(struct port *port, bool *update_slave_arr)
{
struct bonding *bond = __get_bond_by_port(port);
+ struct aggregator *aggregator;
mux_states_t last_state;
/* keep current State Machine state to compare later if it was
@@ -1036,6 +1037,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
*/
last_state = port->sm_mux_state;
+ aggregator = rcu_dereference(port->aggregator);
if (port->sm_vars & AD_PORT_BEGIN) {
port->sm_mux_state = AD_MUX_DETACHED;
} else {
@@ -1055,7 +1057,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
* cycle to update ready variable, we check
* READY_N and update READY here
*/
- __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
+ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator));
port->sm_mux_state = AD_MUX_DETACHED;
break;
}
@@ -1070,7 +1072,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
* update ready variable, we check READY_N and update
* READY here
*/
- __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
+ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator));
/* if the wait_while_timer expired, and the port is
* in READY state, move to ATTACHED state
@@ -1086,7 +1088,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
if ((port->sm_vars & AD_PORT_SELECTED) &&
(port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) &&
!__check_agg_selection_timer(port)) {
- if (port->aggregator->is_active) {
+ if (aggregator->is_active) {
int state = AD_MUX_COLLECTING_DISTRIBUTING;
if (!bond->params.coupled_control)
@@ -1102,9 +1104,9 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
* cycle to update ready variable, we check
* READY_N and update READY here
*/
- __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
+ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator));
port->sm_mux_state = AD_MUX_DETACHED;
- } else if (port->aggregator->is_active) {
+ } else if (aggregator->is_active) {
port->actor_oper_port_state |=
LACP_STATE_SYNCHRONIZATION;
}
@@ -1115,7 +1117,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
* sure that a collecting distributing
* port in an active aggregator is enabled
*/
- if (port->aggregator->is_active &&
+ if (aggregator->is_active &&
!__port_is_collecting_distributing(port)) {
__enable_port(port);
*update_slave_arr = true;
@@ -1134,7 +1136,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
*/
struct slave *slave = port->slave;
- if (port->aggregator->is_active &&
+ if (aggregator->is_active &&
bond_is_slave_rx_disabled(slave)) {
ad_enable_collecting(port);
*update_slave_arr = true;
@@ -1154,8 +1156,8 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
* sure that a collecting distributing
* port in an active aggregator is enabled
*/
- if (port->aggregator &&
- port->aggregator->is_active &&
+ if (aggregator &&
+ aggregator->is_active &&
!__port_is_collecting_distributing(port)) {
__enable_port(port);
*update_slave_arr = true;
@@ -1187,7 +1189,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0);
break;
case AD_MUX_ATTACHED:
- if (port->aggregator->is_active)
+ if (aggregator->is_active)
port->actor_oper_port_state |=
LACP_STATE_SYNCHRONIZATION;
else
@@ -1561,9 +1563,9 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
bond = __get_bond_by_port(port);
/* if the port is connected to other aggregator, detach it */
- if (port->aggregator) {
+ temp_aggregator = rcu_dereference(port->aggregator);
+ if (temp_aggregator) {
/* detach the port from its former aggregator */
- temp_aggregator = port->aggregator;
for (curr_port = temp_aggregator->lag_ports; curr_port;
last_port = curr_port,
curr_port = curr_port->next_port_in_aggregator) {
@@ -1586,7 +1588,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
/* clear the port's relations to this
* aggregator
*/
- port->aggregator = NULL;
+ RCU_INIT_POINTER(port->aggregator, NULL);
port->next_port_in_aggregator = NULL;
port->actor_port_aggregator_identifier = 0;
@@ -1609,7 +1611,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
port->slave->bond->dev->name,
port->slave->dev->name,
port->actor_port_number,
- port->aggregator->aggregator_identifier);
+ temp_aggregator->aggregator_identifier);
}
}
/* search on all aggregators for a suitable aggregator for this port */
@@ -1633,15 +1635,15 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
)
) {
/* attach to the founded aggregator */
- port->aggregator = aggregator;
+ rcu_assign_pointer(port->aggregator, aggregator);
port->actor_port_aggregator_identifier =
- port->aggregator->aggregator_identifier;
+ aggregator->aggregator_identifier;
port->next_port_in_aggregator = aggregator->lag_ports;
- port->aggregator->num_of_ports++;
+ aggregator->num_of_ports++;
aggregator->lag_ports = port;
slave_dbg(bond->dev, slave->dev, "Port %d joined LAG %d (existing LAG)\n",
port->actor_port_number,
- port->aggregator->aggregator_identifier);
+ aggregator->aggregator_identifier);
/* mark this port as selected */
port->sm_vars |= AD_PORT_SELECTED;
@@ -1656,39 +1658,40 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
if (!found) {
if (free_aggregator) {
/* assign port a new aggregator */
- port->aggregator = free_aggregator;
port->actor_port_aggregator_identifier =
- port->aggregator->aggregator_identifier;
+ free_aggregator->aggregator_identifier;
/* update the new aggregator's parameters
* if port was responsed from the end-user
*/
if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS)
/* if port is full duplex */
- port->aggregator->is_individual = false;
+ free_aggregator->is_individual = false;
else
- port->aggregator->is_individual = true;
+ free_aggregator->is_individual = true;
- port->aggregator->actor_admin_aggregator_key =
+ free_aggregator->actor_admin_aggregator_key =
port->actor_admin_port_key;
- port->aggregator->actor_oper_aggregator_key =
+ free_aggregator->actor_oper_aggregator_key =
port->actor_oper_port_key;
- port->aggregator->partner_system =
+ free_aggregator->partner_system =
port->partner_oper.system;
- port->aggregator->partner_system_priority =
+ free_aggregator->partner_system_priority =
port->partner_oper.system_priority;
- port->aggregator->partner_oper_aggregator_key = port->partner_oper.key;
- port->aggregator->receive_state = 1;
- port->aggregator->transmit_state = 1;
- port->aggregator->lag_ports = port;
- port->aggregator->num_of_ports++;
+ free_aggregator->partner_oper_aggregator_key = port->partner_oper.key;
+ free_aggregator->receive_state = 1;
+ free_aggregator->transmit_state = 1;
+ free_aggregator->lag_ports = port;
+ free_aggregator->num_of_ports++;
+
+ rcu_assign_pointer(port->aggregator, free_aggregator);
/* mark this port as selected */
port->sm_vars |= AD_PORT_SELECTED;
slave_dbg(bond->dev, port->slave->dev, "Port %d joined LAG %d (new LAG)\n",
port->actor_port_number,
- port->aggregator->aggregator_identifier);
+ free_aggregator->aggregator_identifier);
} else {
slave_err(bond->dev, port->slave->dev,
"Port %d did not find a suitable aggregator\n",
@@ -1700,13 +1703,12 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
* in all aggregator's ports, else set ready=FALSE in all
* aggregator's ports
*/
- __set_agg_ports_ready(port->aggregator,
- __agg_ports_are_ready(port->aggregator));
+ aggregator = rcu_dereference(port->aggregator);
+ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator));
- aggregator = __get_first_agg(port);
- ad_agg_selection_logic(aggregator, update_slave_arr);
+ ad_agg_selection_logic(__get_first_agg(port), update_slave_arr);
- if (!port->aggregator->is_active)
+ if (!aggregator->is_active)
port->actor_oper_port_state &= ~LACP_STATE_SYNCHRONIZATION;
}
@@ -2075,13 +2077,15 @@ static void ad_initialize_port(struct port *port, const struct bond_params *bond
*/
static void ad_enable_collecting(struct port *port)
{
- if (port->aggregator->is_active) {
+ struct aggregator *aggregator = rcu_dereference(port->aggregator);
+
+ if (aggregator->is_active) {
struct slave *slave = port->slave;
slave_dbg(slave->bond->dev, slave->dev,
"Enabling collecting on port %d (LAG %d)\n",
port->actor_port_number,
- port->aggregator->aggregator_identifier);
+ aggregator->aggregator_identifier);
__enable_collecting_port(port);
}
}
@@ -2093,11 +2097,13 @@ static void ad_enable_collecting(struct port *port)
*/
static void ad_disable_distributing(struct port *port, bool *update_slave_arr)
{
- if (port->aggregator && __agg_has_partner(port->aggregator)) {
+ struct aggregator *aggregator = rcu_dereference(port->aggregator);
+
+ if (aggregator && __agg_has_partner(aggregator)) {
slave_dbg(port->slave->bond->dev, port->slave->dev,
"Disabling distributing on port %d (LAG %d)\n",
port->actor_port_number,
- port->aggregator->aggregator_identifier);
+ aggregator->aggregator_identifier);
__disable_distributing_port(port);
/* Slave array needs an update */
*update_slave_arr = true;
@@ -2114,11 +2120,13 @@ static void ad_disable_distributing(struct port *port, bool *update_slave_arr)
static void ad_enable_collecting_distributing(struct port *port,
bool *update_slave_arr)
{
- if (port->aggregator->is_active) {
+ struct aggregator *aggregator = rcu_dereference(port->aggregator);
+
+ if (aggregator->is_active) {
slave_dbg(port->slave->bond->dev, port->slave->dev,
"Enabling port %d (LAG %d)\n",
port->actor_port_number,
- port->aggregator->aggregator_identifier);
+ aggregator->aggregator_identifier);
__enable_port(port);
/* Slave array needs update */
*update_slave_arr = true;
@@ -2135,11 +2143,13 @@ static void ad_enable_collecting_distributing(struct port *port,
static void ad_disable_collecting_distributing(struct port *port,
bool *update_slave_arr)
{
- if (port->aggregator && __agg_has_partner(port->aggregator)) {
+ struct aggregator *aggregator = rcu_dereference(port->aggregator);
+
+ if (aggregator && __agg_has_partner(aggregator)) {
slave_dbg(port->slave->bond->dev, port->slave->dev,
"Disabling port %d (LAG %d)\n",
port->actor_port_number,
- port->aggregator->aggregator_identifier);
+ aggregator->aggregator_identifier);
__disable_port(port);
/* Slave array needs an update */
*update_slave_arr = true;
@@ -2379,7 +2389,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
*/
for (temp_port = aggregator->lag_ports; temp_port;
temp_port = temp_port->next_port_in_aggregator) {
- temp_port->aggregator = new_aggregator;
+ rcu_assign_pointer(temp_port->aggregator, new_aggregator);
temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier;
}
@@ -2848,15 +2858,16 @@ int bond_3ad_set_carrier(struct bonding *bond)
int __bond_3ad_get_active_agg_info(struct bonding *bond,
struct ad_info *ad_info)
{
- struct aggregator *aggregator = NULL;
+ struct aggregator *aggregator = NULL, *tmp;
struct list_head *iter;
struct slave *slave;
struct port *port;
bond_for_each_slave_rcu(bond, slave, iter) {
port = &(SLAVE_AD_INFO(slave)->port);
- if (port->aggregator && port->aggregator->is_active) {
- aggregator = port->aggregator;
+ tmp = rcu_dereference(port->aggregator);
+ if (tmp && tmp->is_active) {
+ aggregator = tmp;
break;
}
}
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index a5484d11553d..eb49ce486992 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1435,7 +1435,7 @@ static void bond_poll_controller(struct net_device *bond_dev)
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
struct aggregator *agg =
- SLAVE_AD_INFO(slave)->port.aggregator;
+ rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator);
if (agg &&
agg->aggregator_identifier != ad_info.aggregator_id)
@@ -5181,15 +5181,16 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
spin_unlock_bh(&bond->mode_lock);
agg_id = ad_info.aggregator_id;
}
+ rcu_read_lock();
bond_for_each_slave(bond, slave, iter) {
if (skipslave == slave)
continue;
all_slaves->arr[all_slaves->count++] = slave;
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
- struct aggregator *agg;
+ const struct aggregator *agg;
- agg = SLAVE_AD_INFO(slave)->port.aggregator;
+ agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator);
if (!agg || agg->aggregator_identifier != agg_id)
continue;
}
@@ -5201,6 +5202,7 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
usable_slaves->arr[usable_slaves->count++] = slave;
}
+ rcu_read_unlock();
bond_set_slave_arr(bond, usable_slaves, all_slaves);
return ret;
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index 286f11c517f7..c7d3e0602c83 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -29,6 +29,8 @@ static size_t bond_get_slave_size(const struct net_device *bond_dev,
nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE */
nla_total_size(sizeof(s32)) + /* IFLA_BOND_SLAVE_PRIO */
nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_ACTOR_PORT_PRIO */
+ nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE */
+ nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE */
0;
}
@@ -64,20 +66,29 @@ static int bond_fill_slave_info(struct sk_buff *skb,
const struct port *ad_port;
ad_port = &SLAVE_AD_INFO(slave)->port;
- agg = SLAVE_AD_INFO(slave)->port.aggregator;
+ rcu_read_lock();
+ agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator);
if (agg) {
if (nla_put_u16(skb, IFLA_BOND_SLAVE_AD_AGGREGATOR_ID,
agg->aggregator_identifier))
- goto nla_put_failure;
+ goto nla_put_failure_rcu;
if (nla_put_u8(skb,
IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE,
ad_port->actor_oper_port_state))
- goto nla_put_failure;
+ goto nla_put_failure_rcu;
if (nla_put_u16(skb,
IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE,
ad_port->partner_oper.port_state))
- goto nla_put_failure;
+ goto nla_put_failure_rcu;
+
+ if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE,
+ ad_port->sm_churn_actor_state))
+ goto nla_put_failure_rcu;
+ if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE,
+ ad_port->sm_churn_partner_state))
+ goto nla_put_failure_rcu;
}
+ rcu_read_unlock();
if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO,
SLAVE_AD_INFO(slave)->port_priority))
@@ -86,6 +97,8 @@ static int bond_fill_slave_info(struct sk_buff *skb,
return 0;
+nla_put_failure_rcu:
+ rcu_read_unlock();
nla_put_failure:
return -EMSGSIZE;
}
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index 7edf72ec816a..0c0146b76177 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -187,6 +187,7 @@ static void bond_info_show_master(struct seq_file *seq)
}
}
+/* Note: runs under rcu_read_lock() */
static void bond_info_show_slave(struct seq_file *seq,
const struct slave *slave)
{
@@ -213,7 +214,7 @@ static void bond_info_show_slave(struct seq_file *seq,
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
const struct port *port = &SLAVE_AD_INFO(slave)->port;
- const struct aggregator *agg = port->aggregator;
+ const struct aggregator *agg = rcu_dereference(port->aggregator);
if (agg) {
seq_printf(seq, "Aggregator ID: %d\n",
diff --git a/drivers/net/bonding/bond_sysfs_slave.c b/drivers/net/bonding/bond_sysfs_slave.c
index 36d0e8440b5b..fc6fe7181789 100644
--- a/drivers/net/bonding/bond_sysfs_slave.c
+++ b/drivers/net/bonding/bond_sysfs_slave.c
@@ -62,10 +62,15 @@ static ssize_t ad_aggregator_id_show(struct slave *slave, char *buf)
const struct aggregator *agg;
if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) {
- agg = SLAVE_AD_INFO(slave)->port.aggregator;
- if (agg)
- return sysfs_emit(buf, "%d\n",
- agg->aggregator_identifier);
+ rcu_read_lock();
+ agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator);
+ if (agg) {
+ ssize_t res = sysfs_emit(buf, "%d\n",
+ agg->aggregator_identifier);
+ rcu_read_unlock();
+ return res;
+ }
+ rcu_read_unlock();
}
return sysfs_emit(buf, "N/A\n");
@@ -78,7 +83,7 @@ static ssize_t ad_actor_oper_port_state_show(struct slave *slave, char *buf)
if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) {
ad_port = &SLAVE_AD_INFO(slave)->port;
- if (ad_port->aggregator)
+ if (rcu_access_pointer(ad_port->aggregator))
return sysfs_emit(buf, "%u\n",
ad_port->actor_oper_port_state);
}
@@ -93,7 +98,7 @@ static ssize_t ad_partner_oper_port_state_show(struct slave *slave, char *buf)
if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) {
ad_port = &SLAVE_AD_INFO(slave)->port;
- if (ad_port->aggregator)
+ if (rcu_access_pointer(ad_port->aggregator))
return sysfs_emit(buf, "%u\n",
ad_port->partner_oper.port_state);
}
diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c
index 31fa94dac627..c35cef01ec26 100644
--- a/drivers/net/dsa/realtek/rtl8365mb.c
+++ b/drivers/net/dsa/realtek/rtl8365mb.c
@@ -216,7 +216,7 @@
(_extint) == 2 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1 : \
0x0)
#define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(_extint) \
- (0xF << (((_extint) % 2)))
+ (0xF << (((_extint) % 2) * 4))
#define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET(_extint) \
(((_extint) % 2) * 4)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 91cb63a32d99..83882a8953d2 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -76,7 +76,7 @@ static void airoha_set_macaddr(struct airoha_gdm_port *port, const u8 *addr)
struct airoha_eth *eth = port->qdma->eth;
u32 val, reg;
- reg = airhoa_is_lan_gdm_port(port) ? REG_FE_LAN_MAC_H
+ reg = airoha_is_lan_gdm_port(port) ? REG_FE_LAN_MAC_H
: REG_FE_WAN_MAC_H;
val = (addr[0] << 16) | (addr[1] << 8) | addr[2];
airoha_fe_wr(eth, reg, val);
@@ -107,19 +107,7 @@ static int airoha_set_vip_for_gdm_port(struct airoha_gdm_port *port,
struct airoha_eth *eth = port->qdma->eth;
u32 vip_port;
- switch (port->id) {
- case AIROHA_GDM3_IDX:
- /* FIXME: handle XSI_PCIE1_PORT */
- vip_port = XSI_PCIE0_VIP_PORT_MASK;
- break;
- case AIROHA_GDM4_IDX:
- /* FIXME: handle XSI_USB_PORT */
- vip_port = XSI_ETH_VIP_PORT_MASK;
- break;
- default:
- return 0;
- }
-
+ vip_port = eth->soc->ops.get_vip_port(port, port->nbq);
if (enable) {
airoha_fe_set(eth, REG_FE_VIP_PORT_EN, vip_port);
airoha_fe_set(eth, REG_FE_IFC_PORT_EN, vip_port);
@@ -293,16 +281,18 @@ static void airoha_fe_pse_ports_init(struct airoha_eth *eth)
[FE_PSE_PORT_GDM4] = 2,
[FE_PSE_PORT_CDM5] = 2,
};
- u32 all_rsv;
int q;
- all_rsv = airoha_fe_get_pse_all_rsv(eth);
if (airoha_ppe_is_enabled(eth, 1)) {
+ u32 all_rsv;
+
/* hw misses PPE2 oq rsv */
+ all_rsv = airoha_fe_get_pse_all_rsv(eth);
all_rsv += PSE_RSV_PAGES *
pse_port_num_queues[FE_PSE_PORT_PPE2];
+ airoha_fe_rmw(eth, REG_FE_PSE_BUF_SET, PSE_ALLRSV_MASK,
+ FIELD_PREP(PSE_ALLRSV_MASK, all_rsv));
}
- airoha_fe_set(eth, REG_FE_PSE_BUF_SET, all_rsv);
/* CMD1 */
for (q = 0; q < pse_port_num_queues[FE_PSE_PORT_CDM1]; q++)
@@ -584,7 +574,7 @@ static int airoha_qdma_fill_rx_queue(struct airoha_queue *q)
static int airoha_qdma_get_gdm_port(struct airoha_eth *eth,
struct airoha_qdma_desc *desc)
{
- u32 port, sport, msg1 = le32_to_cpu(desc->msg1);
+ u32 port, sport, msg1 = le32_to_cpu(READ_ONCE(desc->msg1));
sport = FIELD_GET(QDMA_ETH_RXMSG_SPORT_MASK, msg1);
switch (sport) {
@@ -612,21 +602,24 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget)
while (done < budget) {
struct airoha_queue_entry *e = &q->entry[q->tail];
struct airoha_qdma_desc *desc = &q->desc[q->tail];
- u32 hash, reason, msg1 = le32_to_cpu(desc->msg1);
- struct page *page = virt_to_head_page(e->buf);
- u32 desc_ctrl = le32_to_cpu(desc->ctrl);
+ u32 hash, reason, msg1, desc_ctrl;
struct airoha_gdm_port *port;
int data_len, len, p;
+ struct page *page;
+ desc_ctrl = le32_to_cpu(READ_ONCE(desc->ctrl));
if (!(desc_ctrl & QDMA_DESC_DONE_MASK))
break;
+ dma_rmb();
+
q->tail = (q->tail + 1) % q->ndesc;
q->queued--;
dma_sync_single_for_cpu(eth->dev, e->dma_addr,
SKB_WITH_OVERHEAD(q->buf_size), dir);
+ page = virt_to_head_page(e->buf);
len = FIELD_GET(QDMA_DESC_LEN_MASK, desc_ctrl);
data_len = q->skb ? q->buf_size
: SKB_WITH_OVERHEAD(q->buf_size);
@@ -670,8 +663,8 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget)
* DMA descriptor. Report DSA tag to the DSA stack
* via skb dst info.
*/
- u32 sptag = FIELD_GET(QDMA_ETH_RXMSG_SPTAG,
- le32_to_cpu(desc->msg0));
+ u32 msg0 = le32_to_cpu(READ_ONCE(desc->msg0));
+ u32 sptag = FIELD_GET(QDMA_ETH_RXMSG_SPTAG, msg0);
if (sptag < ARRAY_SIZE(port->dsa_meta) &&
port->dsa_meta[sptag])
@@ -679,6 +672,7 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget)
&port->dsa_meta[sptag]->dst);
}
+ msg1 = le32_to_cpu(READ_ONCE(desc->msg1));
hash = FIELD_GET(AIROHA_RXD4_FOE_ENTRY, msg1);
if (hash != AIROHA_RXD4_FOE_ENTRY)
skb_set_hash(q->skb, jhash_1word(hash, 0),
@@ -751,14 +745,18 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q,
dma_addr_t dma_addr;
q->buf_size = PAGE_SIZE / 2;
- q->ndesc = ndesc;
q->qdma = qdma;
- q->entry = devm_kzalloc(eth->dev, q->ndesc * sizeof(*q->entry),
+ q->entry = devm_kzalloc(eth->dev, ndesc * sizeof(*q->entry),
GFP_KERNEL);
if (!q->entry)
return -ENOMEM;
+ q->desc = dmam_alloc_coherent(eth->dev, ndesc * sizeof(*q->desc),
+ &dma_addr, GFP_KERNEL);
+ if (!q->desc)
+ return -ENOMEM;
+
q->page_pool = page_pool_create(&pp_params);
if (IS_ERR(q->page_pool)) {
int err = PTR_ERR(q->page_pool);
@@ -767,11 +765,7 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q,
return err;
}
- q->desc = dmam_alloc_coherent(eth->dev, q->ndesc * sizeof(*q->desc),
- &dma_addr, GFP_KERNEL);
- if (!q->desc)
- return -ENOMEM;
-
+ q->ndesc = ndesc;
netif_napi_add(eth->napi_dev, &q->napi, airoha_qdma_rx_napi_poll);
airoha_qdma_wr(qdma, REG_RX_RING_BASE(qid), dma_addr);
@@ -819,6 +813,11 @@ static void airoha_qdma_cleanup_rx_queue(struct airoha_queue *q)
}
q->head = q->tail;
+ /* Set RX_DMA_IDX to RX_CPU_IDX to notify the hw the QDMA RX ring is
+ * empty.
+ */
+ airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK,
+ FIELD_PREP(RX_RING_CPU_IDX_MASK, q->head));
airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK,
FIELD_PREP(RX_RING_DMA_IDX_MASK, q->tail));
}
@@ -844,6 +843,32 @@ static int airoha_qdma_init_rx(struct airoha_qdma *qdma)
return 0;
}
+static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q)
+{
+ struct airoha_qdma *qdma = q->qdma;
+ struct airoha_eth *eth = qdma->eth;
+ int i, qid = q - &qdma->q_tx[0];
+
+ for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
+ struct airoha_gdm_port *port = eth->ports[i];
+ int j;
+
+ if (!port)
+ continue;
+
+ if (port->qdma != qdma)
+ continue;
+
+ for (j = 0; j < port->dev->num_tx_queues; j++) {
+ if (airoha_qdma_get_txq(qdma, j) != qid)
+ continue;
+
+ netif_wake_subqueue(port->dev, j);
+ }
+ }
+ q->txq_stopped = false;
+}
+
static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
{
struct airoha_tx_irq_queue *irq_q;
@@ -915,17 +940,25 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
q->queued--;
if (skb) {
- u16 queue = skb_get_queue_mapping(skb);
struct netdev_queue *txq;
- txq = netdev_get_tx_queue(skb->dev, queue);
+ txq = skb_get_tx_queue(skb->dev, skb);
netdev_tx_completed_queue(txq, 1, skb->len);
- if (netif_tx_queue_stopped(txq) &&
- q->ndesc - q->queued >= q->free_thr)
- netif_tx_wake_queue(txq);
-
dev_kfree_skb_any(skb);
}
+
+ if (q->txq_stopped && q->ndesc - q->queued >= q->free_thr) {
+ /* Since multiple net_device TX queues can share the
+ * same hw QDMA TX queue, there is no guarantee we have
+ * inflight packets queued in hw belonging to a
+ * net_device TX queue stopped in the xmit path.
+ * In order to avoid any potential net_device TX queue
+ * stall, we need to wake all the net_device TX queues
+ * feeding the same hw QDMA TX queue.
+ */
+ airoha_qdma_wake_netdev_txqs(q);
+ }
+
unlock:
spin_unlock_bh(&q->lock);
}
@@ -955,27 +988,27 @@ static int airoha_qdma_init_tx_queue(struct airoha_queue *q,
dma_addr_t dma_addr;
spin_lock_init(&q->lock);
- q->ndesc = size;
q->qdma = qdma;
q->free_thr = 1 + MAX_SKB_FRAGS;
INIT_LIST_HEAD(&q->tx_list);
- q->entry = devm_kzalloc(eth->dev, q->ndesc * sizeof(*q->entry),
+ q->entry = devm_kzalloc(eth->dev, size * sizeof(*q->entry),
GFP_KERNEL);
if (!q->entry)
return -ENOMEM;
- q->desc = dmam_alloc_coherent(eth->dev, q->ndesc * sizeof(*q->desc),
+ q->desc = dmam_alloc_coherent(eth->dev, size * sizeof(*q->desc),
&dma_addr, GFP_KERNEL);
if (!q->desc)
return -ENOMEM;
- for (i = 0; i < q->ndesc; i++) {
+ for (i = 0; i < size; i++) {
u32 val = FIELD_PREP(QDMA_DESC_DONE_MASK, 1);
list_add_tail(&q->entry[i].list, &q->tx_list);
WRITE_ONCE(q->desc[i].ctrl, cpu_to_le32(val));
}
+ q->ndesc = size;
/* xmit ring drop default setting */
airoha_qdma_set(qdma, REG_TX_RING_BLOCKING(qid),
@@ -997,8 +1030,6 @@ static int airoha_qdma_tx_irq_init(struct airoha_tx_irq_queue *irq_q,
struct airoha_eth *eth = qdma->eth;
dma_addr_t dma_addr;
- netif_napi_add_tx(eth->napi_dev, &irq_q->napi,
- airoha_qdma_tx_napi_poll);
irq_q->q = dmam_alloc_coherent(eth->dev, size * sizeof(u32),
&dma_addr, GFP_KERNEL);
if (!irq_q->q)
@@ -1008,6 +1039,9 @@ static int airoha_qdma_tx_irq_init(struct airoha_tx_irq_queue *irq_q,
irq_q->size = size;
irq_q->qdma = qdma;
+ netif_napi_add_tx(eth->napi_dev, &irq_q->napi,
+ airoha_qdma_tx_napi_poll);
+
airoha_qdma_wr(qdma, REG_TX_IRQ_BASE(id), dma_addr);
airoha_qdma_rmw(qdma, REG_TX_IRQ_CFG(id), TX_IRQ_DEPTH_MASK,
FIELD_PREP(TX_IRQ_DEPTH_MASK, size));
@@ -1040,12 +1074,15 @@ static int airoha_qdma_init_tx(struct airoha_qdma *qdma)
static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q)
{
- struct airoha_eth *eth = q->qdma->eth;
- int i;
+ struct airoha_qdma *qdma = q->qdma;
+ struct airoha_eth *eth = qdma->eth;
+ int i, qid = q - &qdma->q_tx[0];
+ u16 index = 0;
spin_lock_bh(&q->lock);
for (i = 0; i < q->ndesc; i++) {
struct airoha_queue_entry *e = &q->entry[i];
+ struct airoha_qdma_desc *desc = &q->desc[i];
if (!e->dma_addr)
continue;
@@ -1056,8 +1093,33 @@ static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q)
e->dma_addr = 0;
e->skb = NULL;
list_add_tail(&e->list, &q->tx_list);
+
+ /* Reset DMA descriptor */
+ WRITE_ONCE(desc->ctrl, 0);
+ WRITE_ONCE(desc->addr, 0);
+ WRITE_ONCE(desc->data, 0);
+ WRITE_ONCE(desc->msg0, 0);
+ WRITE_ONCE(desc->msg1, 0);
+ WRITE_ONCE(desc->msg2, 0);
+
q->queued--;
}
+
+ if (!list_empty(&q->tx_list)) {
+ struct airoha_queue_entry *e;
+
+ e = list_first_entry(&q->tx_list, struct airoha_queue_entry,
+ list);
+ index = e - q->entry;
+ }
+ /* Set TX_DMA_IDX to TX_CPU_IDX to notify the hw the QDMA TX ring is
+ * empty.
+ */
+ airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK,
+ FIELD_PREP(TX_RING_CPU_IDX_MASK, index));
+ airoha_qdma_rmw(qdma, REG_TX_DMA_IDX(qid), TX_RING_DMA_IDX_MASK,
+ FIELD_PREP(TX_RING_DMA_IDX_MASK, index));
+
spin_unlock_bh(&q->lock);
}
@@ -1383,6 +1445,37 @@ static int airoha_qdma_init(struct platform_device *pdev,
return airoha_qdma_hw_init(qdma);
}
+static void airoha_qdma_cleanup(struct airoha_qdma *qdma)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
+ if (!qdma->q_rx[i].ndesc)
+ continue;
+
+ netif_napi_del(&qdma->q_rx[i].napi);
+ airoha_qdma_cleanup_rx_queue(&qdma->q_rx[i]);
+ if (qdma->q_rx[i].page_pool) {
+ page_pool_destroy(qdma->q_rx[i].page_pool);
+ qdma->q_rx[i].page_pool = NULL;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) {
+ if (!qdma->q_tx_irq[i].size)
+ continue;
+
+ netif_napi_del(&qdma->q_tx_irq[i].napi);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) {
+ if (!qdma->q_tx[i].ndesc)
+ continue;
+
+ airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]);
+ }
+}
+
static int airoha_hw_init(struct platform_device *pdev,
struct airoha_eth *eth)
{
@@ -1410,41 +1503,30 @@ static int airoha_hw_init(struct platform_device *pdev,
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) {
err = airoha_qdma_init(pdev, eth, ð->qdma[i]);
if (err)
- return err;
+ goto error;
}
err = airoha_ppe_init(eth);
if (err)
- return err;
+ goto error;
set_bit(DEV_STATE_INITIALIZED, ð->state);
return 0;
+error:
+ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
+ airoha_qdma_cleanup(ð->qdma[i]);
+
+ return err;
}
-static void airoha_hw_cleanup(struct airoha_qdma *qdma)
+static void airoha_hw_cleanup(struct airoha_eth *eth)
{
int i;
- for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
- if (!qdma->q_rx[i].ndesc)
- continue;
-
- netif_napi_del(&qdma->q_rx[i].napi);
- airoha_qdma_cleanup_rx_queue(&qdma->q_rx[i]);
- if (qdma->q_rx[i].page_pool)
- page_pool_destroy(qdma->q_rx[i].page_pool);
- }
-
- for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++)
- netif_napi_del(&qdma->q_tx_irq[i].napi);
-
- for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) {
- if (!qdma->q_tx[i].ndesc)
- continue;
-
- airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]);
- }
+ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
+ airoha_qdma_cleanup(ð->qdma[i]);
+ airoha_ppe_deinit(eth);
}
static void airoha_qdma_start_napi(struct airoha_qdma *qdma)
@@ -1656,14 +1738,11 @@ static int airoha_dev_stop(struct net_device *dev)
{
struct airoha_gdm_port *port = netdev_priv(dev);
struct airoha_qdma *qdma = port->qdma;
- int i, err;
+ int i;
netif_tx_disable(dev);
- err = airoha_set_vip_for_gdm_port(port, false);
- if (err)
- return err;
-
- for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++)
+ airoha_set_vip_for_gdm_port(port, false);
+ for (i = 0; i < dev->num_tx_queues; i++)
netdev_tx_reset_subqueue(dev, i);
if (atomic_dec_and_test(&qdma->users)) {
@@ -1699,7 +1778,7 @@ static int airoha_dev_set_macaddr(struct net_device *dev, void *p)
static int airhoha_set_gdm2_loopback(struct airoha_gdm_port *port)
{
struct airoha_eth *eth = port->qdma->eth;
- u32 val, pse_port, chan, nbq;
+ u32 val, pse_port, chan;
int src_port;
/* Forward the traffic to the proper GDM port */
@@ -1729,9 +1808,7 @@ static int airhoha_set_gdm2_loopback(struct airoha_gdm_port *port)
airoha_fe_clear(eth, REG_FE_VIP_PORT_EN, BIT(AIROHA_GDM2_IDX));
airoha_fe_clear(eth, REG_FE_IFC_PORT_EN, BIT(AIROHA_GDM2_IDX));
- /* XXX: handle XSI_USB_PORT and XSI_PCE1_PORT */
- nbq = port->id == AIROHA_GDM3_IDX && airoha_is_7581(eth) ? 4 : 0;
- src_port = eth->soc->ops.get_src_port_id(port, nbq);
+ src_port = eth->soc->ops.get_src_port_id(port, port->nbq);
if (src_port < 0)
return src_port;
@@ -1925,12 +2002,12 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
struct netdev_queue *txq;
struct airoha_queue *q;
LIST_HEAD(tx_list);
+ int i = 0, qid;
void *data;
- int i, qid;
u16 index;
u8 fport;
- qid = skb_get_queue_mapping(skb) % ARRAY_SIZE(qdma->q_tx);
+ qid = airoha_qdma_get_txq(qdma, skb_get_queue_mapping(skb));
tag = airoha_get_dsa_tag(skb, dev);
msg0 = FIELD_PREP(QDMA_ETH_TXMSG_CHAN_MASK,
@@ -1967,12 +2044,13 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
spin_lock_bh(&q->lock);
- txq = netdev_get_tx_queue(dev, qid);
+ txq = skb_get_tx_queue(dev, skb);
nr_frags = 1 + skb_shinfo(skb)->nr_frags;
if (q->queued + nr_frags >= q->ndesc) {
/* not enough space in the queue */
netif_tx_stop_queue(txq);
+ q->txq_stopped = true;
spin_unlock_bh(&q->lock);
return NETDEV_TX_BUSY;
}
@@ -1984,7 +2062,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
list);
index = e - q->entry;
- for (i = 0; i < nr_frags; i++) {
+ while (true) {
struct airoha_qdma_desc *desc = &q->desc[index];
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
dma_addr_t addr;
@@ -1996,7 +2074,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
goto error_unmap;
list_move_tail(&e->list, &tx_list);
- e->skb = i ? NULL : skb;
+ e->skb = i == nr_frags - 1 ? skb : NULL;
e->dma_addr = addr;
e->dma_len = len;
@@ -2015,6 +2093,9 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
WRITE_ONCE(desc->msg1, cpu_to_le32(msg1));
WRITE_ONCE(desc->msg2, cpu_to_le32(0xffff));
+ if (++i == nr_frags)
+ break;
+
data = skb_frag_address(frag);
len = skb_frag_size(frag);
}
@@ -2022,15 +2103,16 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
skb_tx_timestamp(skb);
netdev_tx_sent_queue(txq, skb->len);
+ if (q->ndesc - q->queued < q->free_thr) {
+ netif_tx_stop_queue(txq);
+ q->txq_stopped = true;
+ }
if (netif_xmit_stopped(txq) || !netdev_xmit_more())
airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid),
TX_RING_CPU_IDX_MASK,
FIELD_PREP(TX_RING_CPU_IDX_MASK, index));
- if (q->ndesc - q->queued < q->free_thr)
- netif_tx_stop_queue(txq);
-
spin_unlock_bh(&q->lock);
return NETDEV_TX_OK;
@@ -2940,6 +3022,8 @@ static int airoha_alloc_gdm_port(struct airoha_eth *eth,
port->qdma = qdma;
port->dev = dev;
port->id = id;
+ /* XXX: Read nbq from DTS */
+ port->nbq = id == AIROHA_GDM3_IDX && airoha_is_7581(eth) ? 4 : 0;
eth->ports[p] = port;
return airoha_metadata_dst_alloc(port);
@@ -3034,7 +3118,7 @@ static int airoha_probe(struct platform_device *pdev)
err = airoha_hw_init(pdev, eth);
if (err)
- goto error_hw_cleanup;
+ goto error_netdev_free;
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
airoha_qdma_start_napi(ð->qdma[i]);
@@ -3063,10 +3147,6 @@ static int airoha_probe(struct platform_device *pdev)
error_napi_stop:
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
airoha_qdma_stop_napi(ð->qdma[i]);
- airoha_ppe_deinit(eth);
-error_hw_cleanup:
- for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
- airoha_hw_cleanup(ð->qdma[i]);
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
@@ -3078,6 +3158,8 @@ static int airoha_probe(struct platform_device *pdev)
unregister_netdev(port->dev);
airoha_metadata_dst_free(port);
}
+ airoha_hw_cleanup(eth);
+error_netdev_free:
free_netdev(eth->napi_dev);
platform_set_drvdata(pdev, NULL);
@@ -3089,10 +3171,8 @@ static void airoha_remove(struct platform_device *pdev)
struct airoha_eth *eth = platform_get_drvdata(pdev);
int i;
- for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) {
+ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
airoha_qdma_stop_napi(ð->qdma[i]);
- airoha_hw_cleanup(ð->qdma[i]);
- }
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
@@ -3103,9 +3183,9 @@ static void airoha_remove(struct platform_device *pdev)
unregister_netdev(port->dev);
airoha_metadata_dst_free(port);
}
- free_netdev(eth->napi_dev);
+ airoha_hw_cleanup(eth);
- airoha_ppe_deinit(eth);
+ free_netdev(eth->napi_dev);
platform_set_drvdata(pdev, NULL);
}
@@ -3141,6 +3221,28 @@ static int airoha_en7581_get_src_port_id(struct airoha_gdm_port *port, int nbq)
return -EINVAL;
}
+static u32 airoha_en7581_get_vip_port(struct airoha_gdm_port *port, int nbq)
+{
+ switch (port->id) {
+ case AIROHA_GDM3_IDX:
+ if (nbq == 4)
+ return XSI_PCIE0_VIP_PORT_MASK;
+ if (nbq == 5)
+ return XSI_PCIE1_VIP_PORT_MASK;
+ break;
+ case AIROHA_GDM4_IDX:
+ if (!nbq)
+ return XSI_ETH_VIP_PORT_MASK;
+ if (nbq == 1)
+ return XSI_USB_VIP_PORT_MASK;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static const char * const an7583_xsi_rsts_names[] = {
"xsi-mac",
"hsi0-mac",
@@ -3170,6 +3272,26 @@ static int airoha_an7583_get_src_port_id(struct airoha_gdm_port *port, int nbq)
return -EINVAL;
}
+static u32 airoha_an7583_get_vip_port(struct airoha_gdm_port *port, int nbq)
+{
+ switch (port->id) {
+ case AIROHA_GDM3_IDX:
+ if (!nbq)
+ return XSI_ETH_VIP_PORT_MASK;
+ break;
+ case AIROHA_GDM4_IDX:
+ if (!nbq)
+ return XSI_PCIE0_VIP_PORT_MASK;
+ if (nbq == 1)
+ return XSI_USB_VIP_PORT_MASK;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static const struct airoha_eth_soc_data en7581_soc_data = {
.version = 0x7581,
.xsi_rsts_names = en7581_xsi_rsts_names,
@@ -3177,6 +3299,7 @@ static const struct airoha_eth_soc_data en7581_soc_data = {
.num_ppe = 2,
.ops = {
.get_src_port_id = airoha_en7581_get_src_port_id,
+ .get_vip_port = airoha_en7581_get_vip_port,
},
};
@@ -3187,6 +3310,7 @@ static const struct airoha_eth_soc_data an7583_soc_data = {
.num_ppe = 1,
.ops = {
.get_src_port_id = airoha_an7583_get_src_port_id,
+ .get_vip_port = airoha_an7583_get_vip_port,
},
};
diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
index a97903569335..7098e95f0067 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
@@ -193,6 +193,7 @@ struct airoha_queue {
int ndesc;
int free_thr;
int buf_size;
+ bool txq_stopped;
struct napi_struct napi;
struct page_pool *page_pool;
@@ -536,6 +537,7 @@ struct airoha_gdm_port {
struct airoha_qdma *qdma;
struct net_device *dev;
int id;
+ int nbq;
struct airoha_hw_stats stats;
@@ -576,6 +578,7 @@ struct airoha_eth_soc_data {
int num_ppe;
struct {
int (*get_src_port_id)(struct airoha_gdm_port *port, int nbq);
+ u32 (*get_vip_port)(struct airoha_gdm_port *port, int nbq);
} ops;
};
@@ -627,7 +630,12 @@ u32 airoha_rmw(void __iomem *base, u32 offset, u32 mask, u32 val);
#define airoha_qdma_clear(qdma, offset, val) \
airoha_rmw((qdma)->regs, (offset), (val), 0)
-static inline bool airhoa_is_lan_gdm_port(struct airoha_gdm_port *port)
+static inline u16 airoha_qdma_get_txq(struct airoha_qdma *qdma, u16 qid)
+{
+ return qid % ARRAY_SIZE(qdma->q_tx);
+}
+
+static inline bool airoha_is_lan_gdm_port(struct airoha_gdm_port *port)
{
/* GDM1 port on EN7581 SoC is connected to the lan dsa switch.
* GDM{2,3,4} can be used as wan port connected to an external
diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c
index c2c32b6833df..f2af45f7d66d 100644
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
@@ -111,13 +111,13 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe)
airoha_fe_rmw(eth, REG_PPE_BND_AGE0(i),
PPE_BIND_AGE0_DELTA_NON_L4 |
PPE_BIND_AGE0_DELTA_UDP,
- FIELD_PREP(PPE_BIND_AGE0_DELTA_NON_L4, 1) |
- FIELD_PREP(PPE_BIND_AGE0_DELTA_UDP, 12));
+ FIELD_PREP(PPE_BIND_AGE0_DELTA_NON_L4, 60) |
+ FIELD_PREP(PPE_BIND_AGE0_DELTA_UDP, 60));
airoha_fe_rmw(eth, REG_PPE_BND_AGE1(i),
PPE_BIND_AGE1_DELTA_TCP_FIN |
PPE_BIND_AGE1_DELTA_TCP,
FIELD_PREP(PPE_BIND_AGE1_DELTA_TCP_FIN, 1) |
- FIELD_PREP(PPE_BIND_AGE1_DELTA_TCP, 7));
+ FIELD_PREP(PPE_BIND_AGE1_DELTA_TCP, 60));
airoha_fe_rmw(eth, REG_PPE_TB_HASH_CFG(i),
PPE_SRAM_TABLE_EN_MASK |
@@ -145,7 +145,15 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe)
FIELD_PREP(PPE_DRAM_TB_NUM_ENTRY_MASK,
dram_num_entries));
+ airoha_fe_rmw(eth, REG_PPE_BIND_RATE(i),
+ PPE_BIND_RATE_L2B_BIND_MASK |
+ PPE_BIND_RATE_BIND_MASK,
+ FIELD_PREP(PPE_BIND_RATE_L2B_BIND_MASK, 0x1e) |
+ FIELD_PREP(PPE_BIND_RATE_BIND_MASK, 0x1e));
+
airoha_fe_wr(eth, REG_PPE_HASH_SEED(i), PPE_HASH_SEED);
+ airoha_fe_clear(eth, REG_PPE_PPE_FLOW_CFG(i),
+ PPE_FLOW_CFG_IP6_6RD_MASK);
for (p = 0; p < ARRAY_SIZE(eth->ports); p++)
airoha_fe_rmw(eth, REG_PPE_MTU(i, p),
@@ -323,7 +331,7 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth,
/* For downlink traffic consume SRAM memory for hw
* forwarding descriptors queue.
*/
- if (airhoa_is_lan_gdm_port(port))
+ if (airoha_is_lan_gdm_port(port))
val |= AIROHA_FOE_IB2_FAST_PATH;
if (dsa_port >= 0)
val |= FIELD_PREP(AIROHA_FOE_IB2_NBQ,
@@ -1327,6 +1335,29 @@ static struct airoha_npu *airoha_ppe_npu_get(struct airoha_eth *eth)
return npu;
}
+static int airoha_ppe_wait_for_npu_init(struct airoha_eth *eth)
+{
+ int err;
+ u32 val;
+
+ /* PPE_FLOW_CFG default register value is 0. Since we reset FE
+ * during the device probe we can just check the configured value
+ * is not 0 here.
+ */
+ err = read_poll_timeout(airoha_fe_rr, val, val, USEC_PER_MSEC,
+ 100 * USEC_PER_MSEC, false, eth,
+ REG_PPE_PPE_FLOW_CFG(0));
+ if (err)
+ return err;
+
+ if (airoha_ppe_is_enabled(eth, 1))
+ err = read_poll_timeout(airoha_fe_rr, val, val, USEC_PER_MSEC,
+ 100 * USEC_PER_MSEC, false, eth,
+ REG_PPE_PPE_FLOW_CFG(1));
+
+ return err;
+}
+
static int airoha_ppe_offload_setup(struct airoha_eth *eth)
{
struct airoha_npu *npu = airoha_ppe_npu_get(eth);
@@ -1340,6 +1371,11 @@ static int airoha_ppe_offload_setup(struct airoha_eth *eth)
if (err)
goto error_npu_put;
+ /* Wait for NPU PPE configuration to complete */
+ err = airoha_ppe_wait_for_npu_init(eth);
+ if (err)
+ goto error_npu_put;
+
ppe_num_stats_entries = airoha_ppe_get_total_num_stats_entries(ppe);
if (ppe_num_stats_entries > 0) {
err = npu->ops.ppe_init_stats(npu, ppe->foe_stats_dma,
diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c
index e67b592e5697..8c86789d867a 100644
--- a/drivers/net/ethernet/amazon/ena/ena_com.c
+++ b/drivers/net/ethernet/amazon/ena/ena_com.c
@@ -1782,20 +1782,23 @@ void ena_com_phc_destroy(struct ena_com_dev *ena_dev)
int ena_com_phc_get_timestamp(struct ena_com_dev *ena_dev, u64 *timestamp)
{
- volatile struct ena_admin_phc_resp *resp = ena_dev->phc.virt_addr;
const ktime_t zero_system_time = ktime_set(0, 0);
struct ena_com_phc_info *phc = &ena_dev->phc;
+ volatile struct ena_admin_phc_resp *resp;
ktime_t expire_time;
ktime_t block_time;
unsigned long flags = 0;
int ret = 0;
+ spin_lock_irqsave(&phc->lock, flags);
+
if (!phc->active) {
+ spin_unlock_irqrestore(&phc->lock, flags);
netdev_err(ena_dev->net_device, "PHC feature is not active in the device\n");
return -EOPNOTSUPP;
}
- spin_lock_irqsave(&phc->lock, flags);
+ resp = ena_dev->phc.virt_addr;
/* Check if PHC is in blocked state */
if (unlikely(ktime_compare(phc->system_time, zero_system_time))) {
diff --git a/drivers/net/ethernet/amazon/ena/ena_phc.c b/drivers/net/ethernet/amazon/ena/ena_phc.c
index 7867e893fd15..c2a3ff1ef645 100644
--- a/drivers/net/ethernet/amazon/ena/ena_phc.c
+++ b/drivers/net/ethernet/amazon/ena/ena_phc.c
@@ -46,9 +46,12 @@ static int ena_phc_gettimex64(struct ptp_clock_info *clock_info,
spin_unlock_irqrestore(&phc_info->lock, flags);
+ if (rc)
+ return rc;
+
*ts = ns_to_timespec64(timestamp_nsec);
- return rc;
+ return 0;
}
static int ena_phc_settime64(struct ptp_clock_info *clock_info,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
index e9e38af680c3..39e1b606a75a 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
@@ -371,7 +371,7 @@ static void aq_pci_shutdown(struct pci_dev *pdev)
pci_disable_device(pdev);
if (system_state == SYSTEM_POWER_OFF) {
- pci_wake_from_d3(pdev, false);
+ pci_wake_from_d3(pdev, self->aq_hw->aq_nic_cfg->wol);
pci_set_power_state(pdev, PCI_D3hot);
}
}
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_core.c b/drivers/net/ethernet/broadcom/bnge/bnge_core.c
index b4090283df0f..99d7aeeb2ddc 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_core.c
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_core.c
@@ -73,6 +73,13 @@ static int bnge_func_qcaps(struct bnge_dev *bd)
return rc;
}
+ return 0;
+}
+
+static int bnge_func_qrcaps_qcfg(struct bnge_dev *bd)
+{
+ int rc;
+
rc = bnge_hwrm_func_resc_qcaps(bd);
if (rc) {
dev_err(bd->dev, "query resc caps failure rc: %d\n", rc);
@@ -132,23 +139,28 @@ static int bnge_fw_register_dev(struct bnge_dev *bd)
bnge_hwrm_fw_set_time(bd);
- rc = bnge_hwrm_func_drv_rgtr(bd);
+ /* Get the resources and configuration from firmware */
+ rc = bnge_func_qcaps(bd);
if (rc) {
- dev_err(bd->dev, "Failed to rgtr with firmware rc: %d\n", rc);
+ dev_err(bd->dev, "Failed querying caps rc: %d\n", rc);
return rc;
}
rc = bnge_alloc_ctx_mem(bd);
if (rc) {
dev_err(bd->dev, "Failed to allocate ctx mem rc: %d\n", rc);
- goto err_func_unrgtr;
+ goto err_free_ctx_mem;
}
- /* Get the resources and configuration from firmware */
- rc = bnge_func_qcaps(bd);
+ rc = bnge_hwrm_func_drv_rgtr(bd);
if (rc) {
- dev_err(bd->dev, "Failed initial configuration rc: %d\n", rc);
- rc = -ENODEV;
+ dev_err(bd->dev, "Failed to rgtr with firmware rc: %d\n", rc);
+ goto err_free_ctx_mem;
+ }
+
+ rc = bnge_func_qrcaps_qcfg(bd);
+ if (rc) {
+ dev_err(bd->dev, "Failed querying resources rc: %d\n", rc);
goto err_func_unrgtr;
}
@@ -157,7 +169,9 @@ static int bnge_fw_register_dev(struct bnge_dev *bd)
return 0;
err_func_unrgtr:
- bnge_fw_unregister_dev(bd);
+ bnge_hwrm_func_drv_unrgtr(bd);
+err_free_ctx_mem:
+ bnge_free_ctx_mem(bd);
return rc;
}
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_rmem.c b/drivers/net/ethernet/broadcom/bnge/bnge_rmem.c
index 94f15e08a88c..b066ee887a09 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_rmem.c
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_rmem.c
@@ -324,7 +324,6 @@ int bnge_alloc_ctx_mem(struct bnge_dev *bd)
u32 l2_qps, qp1_qps, max_qps;
u32 ena, entries_sp, entries;
u32 srqs, max_srqs, min;
- u32 num_mr, num_ah;
u32 extra_srqs = 0;
u32 extra_qps = 0;
u32 fast_qpmd_qps;
@@ -390,21 +389,6 @@ int bnge_alloc_ctx_mem(struct bnge_dev *bd)
if (!bnge_is_roce_en(bd))
goto skip_rdma;
- ctxm = &ctx->ctx_arr[BNGE_CTX_MRAV];
- /* 128K extra is needed to accommodate static AH context
- * allocation by f/w.
- */
- num_mr = min_t(u32, ctxm->max_entries / 2, 1024 * 256);
- num_ah = min_t(u32, num_mr, 1024 * 128);
- ctxm->split_entry_cnt = BNGE_CTX_MRAV_AV_SPLIT_ENTRY + 1;
- if (!ctxm->mrav_av_entries || ctxm->mrav_av_entries > num_ah)
- ctxm->mrav_av_entries = num_ah;
-
- rc = bnge_setup_ctxm_pg_tbls(bd, ctxm, num_mr + num_ah, 2);
- if (rc)
- return rc;
- ena |= FUNC_BACKING_STORE_CFG_REQ_ENABLES_MRAV;
-
ctxm = &ctx->ctx_arr[BNGE_CTX_TIM];
rc = bnge_setup_ctxm_pg_tbls(bd, ctxm, l2_qps + qp1_qps + extra_qps, 1);
if (rc)
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 482a31e7b72b..54f71b1e85fc 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1819,15 +1819,15 @@ static struct enet_cb *bcmgenet_put_txcb(struct bcmgenet_priv *priv,
{
struct enet_cb *tx_cb_ptr;
- tx_cb_ptr = ring->cbs;
- tx_cb_ptr += ring->write_ptr - ring->cb_ptr;
-
/* Rewinding local write pointer */
if (ring->write_ptr == ring->cb_ptr)
ring->write_ptr = ring->end_ptr;
else
ring->write_ptr--;
+ tx_cb_ptr = ring->cbs;
+ tx_cb_ptr += ring->write_ptr - ring->cb_ptr;
+
return tx_cb_ptr;
}
@@ -1985,6 +1985,7 @@ static unsigned int bcmgenet_tx_reclaim(struct net_device *dev,
drop = (ring->prod_index - ring->c_index) & DMA_C_INDEX_MASK;
released += drop;
ring->prod_index = ring->c_index & DMA_C_INDEX_MASK;
+ ring->free_bds += drop;
while (drop--) {
cb_ptr = bcmgenet_put_txcb(priv, ring);
skb = cb_ptr->skb;
@@ -1996,6 +1997,7 @@ static unsigned int bcmgenet_tx_reclaim(struct net_device *dev,
}
if (skb)
dev_consume_skb_any(skb);
+ netdev_tx_reset_queue(netdev_get_tx_queue(dev, ring->index));
bcmgenet_tdma_ring_writel(priv, ring->index,
ring->prod_index, TDMA_PROD_INDEX);
wr_ptr = ring->write_ptr * WORDS_PER_BD(priv);
@@ -3475,27 +3477,23 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring)
static void bcmgenet_timeout(struct net_device *dev, unsigned int txqueue)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
- u32 int1_enable = 0;
- unsigned int q;
+ struct bcmgenet_tx_ring *ring = &priv->tx_rings[txqueue];
+ struct netdev_queue *txq = netdev_get_tx_queue(dev, txqueue);
netif_dbg(priv, tx_err, dev, "bcmgenet_timeout\n");
- for (q = 0; q <= priv->hw_params->tx_queues; q++)
- bcmgenet_dump_tx_queue(&priv->tx_rings[q]);
-
- bcmgenet_tx_reclaim_all(dev);
+ bcmgenet_dump_tx_queue(ring);
- for (q = 0; q <= priv->hw_params->tx_queues; q++)
- int1_enable |= (1 << q);
+ bcmgenet_tx_reclaim(dev, ring, true);
- /* Re-enable TX interrupts if disabled */
- bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR);
+ /* Re-enable the TX interrupt for this ring */
+ bcmgenet_intrl2_1_writel(priv, 1 << txqueue, INTRL2_CPU_MASK_CLEAR);
- netif_trans_update(dev);
+ txq_trans_cond_update(txq);
- BCMGENET_STATS64_INC((&priv->tx_rings[txqueue].stats64), errors);
+ BCMGENET_STATS64_INC((&ring->stats64), errors);
- netif_tx_wake_all_queues(dev);
+ netif_tx_wake_queue(txq);
}
#define MAX_MDF_FILTER 17
diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile
index de7b31842233..d0a259e47960 100644
--- a/drivers/net/ethernet/freescale/Makefile
+++ b/drivers/net/ethernet/freescale/Makefile
@@ -22,6 +22,5 @@ ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o
obj-$(CONFIG_FSL_FMAN) += fman/
obj-$(CONFIG_FSL_DPAA_ETH) += dpaa/
-obj-$(CONFIG_FSL_DPAA2_ETH) += dpaa2/
-
+obj-y += dpaa2/
obj-y += enetc/
diff --git a/drivers/net/ethernet/freescale/dpaa2/Kconfig b/drivers/net/ethernet/freescale/dpaa2/Kconfig
index d029b69c3f18..36280e5d99e1 100644
--- a/drivers/net/ethernet/freescale/dpaa2/Kconfig
+++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig
@@ -34,6 +34,10 @@ config FSL_DPAA2_SWITCH
tristate "Freescale DPAA2 Ethernet Switch"
depends on BRIDGE || BRIDGE=n
depends on NET_SWITCHDEV
+ depends on FSL_MC_BUS && FSL_MC_DPIO
+ select PHYLINK
+ select PCS_LYNX
+ select FSL_XGMAC_MDIO
help
Driver for Freescale DPAA2 Ethernet Switch. This driver manages
switch objects discovered on the Freeescale MC bus.
diff --git a/drivers/net/ethernet/freescale/enetc/ntmp.c b/drivers/net/ethernet/freescale/enetc/ntmp.c
index 0c1d343253bf..70bbc5d2d5d4 100644
--- a/drivers/net/ethernet/freescale/enetc/ntmp.c
+++ b/drivers/net/ethernet/freescale/enetc/ntmp.c
@@ -7,6 +7,7 @@
#include <linux/dma-mapping.h>
#include <linux/fsl/netc_global.h>
#include <linux/iopoll.h>
+#include <linux/vmalloc.h>
#include "ntmp_private.h"
@@ -42,6 +43,12 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev,
if (!cbdr->addr_base)
return -ENOMEM;
+ cbdr->swcbd = vcalloc(cbd_num, sizeof(struct netc_swcbd));
+ if (!cbdr->swcbd) {
+ dma_free_coherent(dev, size, cbdr->addr_base, cbdr->dma_base);
+ return -ENOMEM;
+ }
+
cbdr->dma_size = size;
cbdr->bd_num = cbd_num;
cbdr->regs = *regs;
@@ -52,10 +59,10 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev,
cbdr->addr_base_align = PTR_ALIGN(cbdr->addr_base,
NTMP_BASE_ADDR_ALIGN);
- spin_lock_init(&cbdr->ring_lock);
+ mutex_init(&cbdr->ring_lock);
cbdr->next_to_use = netc_read(cbdr->regs.pir);
- cbdr->next_to_clean = netc_read(cbdr->regs.cir);
+ cbdr->next_to_clean = netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX;
/* Step 1: Configure the base address of the Control BD Ring */
netc_write(cbdr->regs.bar0, lower_32_bits(cbdr->dma_base_align));
@@ -71,10 +78,24 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev,
}
EXPORT_SYMBOL_GPL(ntmp_init_cbdr);
+static void ntmp_free_data_mem(struct device *dev, struct netc_swcbd *swcbd)
+{
+ if (unlikely(!swcbd->buf))
+ return;
+
+ dma_free_coherent(dev, swcbd->size + NTMP_DATA_ADDR_ALIGN,
+ swcbd->buf, swcbd->dma);
+}
+
void ntmp_free_cbdr(struct netc_cbdr *cbdr)
{
/* Disable the Control BD Ring */
netc_write(cbdr->regs.mr, 0);
+
+ for (int i = 0; i < cbdr->bd_num; i++)
+ ntmp_free_data_mem(cbdr->dev, &cbdr->swcbd[i]);
+
+ vfree(cbdr->swcbd);
dma_free_coherent(cbdr->dev, cbdr->dma_size, cbdr->addr_base,
cbdr->dma_base);
memset(cbdr, 0, sizeof(*cbdr));
@@ -94,40 +115,59 @@ static union netc_cbd *ntmp_get_cbd(struct netc_cbdr *cbdr, int index)
static void ntmp_clean_cbdr(struct netc_cbdr *cbdr)
{
- union netc_cbd *cbd;
- int i;
+ int i = cbdr->next_to_clean;
+
+ while ((netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX) != i) {
+ union netc_cbd *cbd = ntmp_get_cbd(cbdr, i);
+ struct netc_swcbd *swcbd = &cbdr->swcbd[i];
- i = cbdr->next_to_clean;
- while (netc_read(cbdr->regs.cir) != i) {
- cbd = ntmp_get_cbd(cbdr, i);
+ ntmp_free_data_mem(cbdr->dev, swcbd);
+ memset(swcbd, 0, sizeof(*swcbd));
memset(cbd, 0, sizeof(*cbd));
i = (i + 1) % cbdr->bd_num;
}
+ dma_wmb();
cbdr->next_to_clean = i;
}
-static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd)
+static void ntmp_select_and_lock_cbdr(struct ntmp_user *user,
+ struct netc_cbdr **cbdr)
+{
+ /* Currently only ENETC is supported, and it has only one command
+ * BD ring.
+ */
+ *cbdr = &user->ring[0];
+
+ mutex_lock(&(*cbdr)->ring_lock);
+}
+
+static void ntmp_unlock_cbdr(struct netc_cbdr *cbdr)
+{
+ mutex_unlock(&cbdr->ring_lock);
+}
+
+static int netc_xmit_ntmp_cmd(struct netc_cbdr *cbdr, union netc_cbd *cbd,
+ struct netc_swcbd *swcbd)
{
union netc_cbd *cur_cbd;
- struct netc_cbdr *cbdr;
- int i, err;
+ int i, err, used_bds;
u16 status;
u32 val;
- /* Currently only i.MX95 ENETC is supported, and it only has one
- * command BD ring
- */
- cbdr = &user->ring[0];
-
- spin_lock_bh(&cbdr->ring_lock);
-
- if (unlikely(!ntmp_get_free_cbd_num(cbdr)))
+ used_bds = cbdr->bd_num - ntmp_get_free_cbd_num(cbdr);
+ if (unlikely(used_bds >= NETC_CBDR_CLEAN_WORK)) {
ntmp_clean_cbdr(cbdr);
+ if (unlikely(!ntmp_get_free_cbd_num(cbdr))) {
+ ntmp_free_data_mem(cbdr->dev, swcbd);
+ return -EBUSY;
+ }
+ }
i = cbdr->next_to_use;
cur_cbd = ntmp_get_cbd(cbdr, i);
*cur_cbd = *cbd;
+ cbdr->swcbd[i] = *swcbd;
dma_wmb();
/* Update producer index of both software and hardware */
@@ -135,11 +175,17 @@ static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd)
cbdr->next_to_use = i;
netc_write(cbdr->regs.pir, i);
- err = read_poll_timeout_atomic(netc_read, val, val == i,
- NETC_CBDR_DELAY_US, NETC_CBDR_TIMEOUT,
- true, cbdr->regs.cir);
+ err = read_poll_timeout(netc_read, val,
+ (val & NETC_CBDRCIR_INDEX) == i,
+ NETC_CBDR_DELAY_US, NETC_CBDR_TIMEOUT,
+ true, cbdr->regs.cir);
if (unlikely(err))
- goto cbdr_unlock;
+ return err;
+
+ if (unlikely(val & NETC_CBDRCIR_SBE)) {
+ dev_err(cbdr->dev, "Command BD system bus error\n");
+ return -EIO;
+ }
dma_rmb();
/* Get the writeback command BD, because the caller may need
@@ -150,40 +196,29 @@ static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd)
/* Check the writeback error status */
status = le16_to_cpu(cbd->resp_hdr.error_rr) & NTMP_RESP_ERROR;
if (unlikely(status)) {
- err = -EIO;
- dev_err(user->dev, "Command BD error: 0x%04x\n", status);
+ dev_err(cbdr->dev, "Command BD error: 0x%04x\n", status);
+ return -EIO;
}
- ntmp_clean_cbdr(cbdr);
- dma_wmb();
-
-cbdr_unlock:
- spin_unlock_bh(&cbdr->ring_lock);
-
- return err;
+ return 0;
}
-static int ntmp_alloc_data_mem(struct ntmp_dma_buf *data, void **buf_align)
+static int ntmp_alloc_data_mem(struct device *dev, struct netc_swcbd *swcbd,
+ void **buf_align)
{
void *buf;
- buf = dma_alloc_coherent(data->dev, data->size + NTMP_DATA_ADDR_ALIGN,
- &data->dma, GFP_KERNEL);
+ buf = dma_alloc_coherent(dev, swcbd->size + NTMP_DATA_ADDR_ALIGN,
+ &swcbd->dma, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- data->buf = buf;
+ swcbd->buf = buf;
*buf_align = PTR_ALIGN(buf, NTMP_DATA_ADDR_ALIGN);
return 0;
}
-static void ntmp_free_data_mem(struct ntmp_dma_buf *data)
-{
- dma_free_coherent(data->dev, data->size + NTMP_DATA_ADDR_ALIGN,
- data->buf, data->dma);
-}
-
static void ntmp_fill_request_hdr(union netc_cbd *cbd, dma_addr_t dma,
int len, int table_id, int cmd,
int access_method)
@@ -234,37 +269,39 @@ static int ntmp_delete_entry_by_id(struct ntmp_user *user, int tbl_id,
u8 tbl_ver, u32 entry_id, u32 req_len,
u32 resp_len)
{
- struct ntmp_dma_buf data = {
- .dev = user->dev,
+ struct netc_swcbd swcbd = {
.size = max(req_len, resp_len),
};
struct ntmp_req_by_eid *req;
+ struct netc_cbdr *cbdr;
union netc_cbd cbd;
int err;
- err = ntmp_alloc_data_mem(&data, (void **)&req);
+ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
ntmp_fill_crd_eid(req, tbl_ver, 0, 0, entry_id);
- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(req_len, resp_len),
+ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(req_len, resp_len),
tbl_id, NTMP_CMD_DELETE, NTMP_AM_ENTRY_ID);
- err = netc_xmit_ntmp_cmd(user, &cbd);
+ ntmp_select_and_lock_cbdr(user, &cbdr);
+ err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd);
if (err)
dev_err(user->dev,
"Failed to delete entry 0x%x of %s, err: %pe",
entry_id, ntmp_table_name(tbl_id), ERR_PTR(err));
-
- ntmp_free_data_mem(&data);
+ ntmp_unlock_cbdr(cbdr);
return err;
}
-static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id,
- u32 len, struct ntmp_req_by_eid *req,
- dma_addr_t dma, bool compare_eid)
+static int ntmp_query_entry_by_id(struct netc_cbdr *cbdr, int tbl_id,
+ struct ntmp_req_by_eid *req,
+ struct netc_swcbd *swcbd,
+ bool compare_eid)
{
+ u32 len = NTMP_LEN(sizeof(*req), swcbd->size);
struct ntmp_cmn_resp_query *resp;
int cmd = NTMP_CMD_QUERY;
union netc_cbd cbd;
@@ -276,10 +313,11 @@ static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id,
cmd = NTMP_CMD_QU;
/* Request header */
- ntmp_fill_request_hdr(&cbd, dma, len, tbl_id, cmd, NTMP_AM_ENTRY_ID);
- err = netc_xmit_ntmp_cmd(user, &cbd);
+ ntmp_fill_request_hdr(&cbd, swcbd->dma, len, tbl_id, cmd,
+ NTMP_AM_ENTRY_ID);
+ err = netc_xmit_ntmp_cmd(cbdr, &cbd, swcbd);
if (err) {
- dev_err(user->dev,
+ dev_err(cbdr->dev,
"Failed to query entry 0x%x of %s, err: %pe\n",
entry_id, ntmp_table_name(tbl_id), ERR_PTR(err));
return err;
@@ -293,7 +331,7 @@ static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id,
resp = (struct ntmp_cmn_resp_query *)req;
if (unlikely(le32_to_cpu(resp->entry_id) != entry_id)) {
- dev_err(user->dev,
+ dev_err(cbdr->dev,
"%s: query EID 0x%x doesn't match response EID 0x%x\n",
ntmp_table_name(tbl_id), entry_id, le32_to_cpu(resp->entry_id));
return -EIO;
@@ -305,15 +343,15 @@ static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id,
int ntmp_maft_add_entry(struct ntmp_user *user, u32 entry_id,
struct maft_entry_data *maft)
{
- struct ntmp_dma_buf data = {
- .dev = user->dev,
+ struct netc_swcbd swcbd = {
.size = sizeof(struct maft_req_add),
};
struct maft_req_add *req;
+ struct netc_cbdr *cbdr;
union netc_cbd cbd;
int err;
- err = ntmp_alloc_data_mem(&data, (void **)&req);
+ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
@@ -322,14 +360,15 @@ int ntmp_maft_add_entry(struct ntmp_user *user, u32 entry_id,
req->keye = maft->keye;
req->cfge = maft->cfge;
- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(data.size, 0),
+ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(swcbd.size, 0),
NTMP_MAFT_ID, NTMP_CMD_ADD, NTMP_AM_ENTRY_ID);
- err = netc_xmit_ntmp_cmd(user, &cbd);
+
+ ntmp_select_and_lock_cbdr(user, &cbdr);
+ err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd);
if (err)
dev_err(user->dev, "Failed to add MAFT entry 0x%x, err: %pe\n",
entry_id, ERR_PTR(err));
-
- ntmp_free_data_mem(&data);
+ ntmp_unlock_cbdr(cbdr);
return err;
}
@@ -338,31 +377,31 @@ EXPORT_SYMBOL_GPL(ntmp_maft_add_entry);
int ntmp_maft_query_entry(struct ntmp_user *user, u32 entry_id,
struct maft_entry_data *maft)
{
- struct ntmp_dma_buf data = {
- .dev = user->dev,
+ struct netc_swcbd swcbd = {
.size = sizeof(struct maft_resp_query),
};
struct maft_resp_query *resp;
struct ntmp_req_by_eid *req;
+ struct netc_cbdr *cbdr;
int err;
- err = ntmp_alloc_data_mem(&data, (void **)&req);
+ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
ntmp_fill_crd_eid(req, user->tbl.maft_ver, 0, 0, entry_id);
- err = ntmp_query_entry_by_id(user, NTMP_MAFT_ID,
- NTMP_LEN(sizeof(*req), data.size),
- req, data.dma, true);
+
+ ntmp_select_and_lock_cbdr(user, &cbdr);
+ err = ntmp_query_entry_by_id(cbdr, NTMP_MAFT_ID, req, &swcbd, true);
if (err)
- goto end;
+ goto unlock_cbdr;
resp = (struct maft_resp_query *)req;
maft->keye = resp->keye;
maft->cfge = resp->cfge;
-end:
- ntmp_free_data_mem(&data);
+unlock_cbdr:
+ ntmp_unlock_cbdr(cbdr);
return err;
}
@@ -378,8 +417,9 @@ EXPORT_SYMBOL_GPL(ntmp_maft_delete_entry);
int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table,
int count)
{
- struct ntmp_dma_buf data = {.dev = user->dev};
struct rsst_req_update *req;
+ struct netc_swcbd swcbd;
+ struct netc_cbdr *cbdr;
union netc_cbd cbd;
int err, i;
@@ -387,8 +427,8 @@ int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table,
/* HW only takes in a full 64 entry table */
return -EINVAL;
- data.size = struct_size(req, groups, count);
- err = ntmp_alloc_data_mem(&data, (void **)&req);
+ swcbd.size = struct_size(req, groups, count);
+ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
@@ -398,15 +438,15 @@ int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table,
for (i = 0; i < count; i++)
req->groups[i] = (u8)(table[i]);
- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(data.size, 0),
+ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(swcbd.size, 0),
NTMP_RSST_ID, NTMP_CMD_UPDATE, NTMP_AM_ENTRY_ID);
- err = netc_xmit_ntmp_cmd(user, &cbd);
+ ntmp_select_and_lock_cbdr(user, &cbdr);
+ err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd);
if (err)
dev_err(user->dev, "Failed to update RSST entry, err: %pe\n",
ERR_PTR(err));
-
- ntmp_free_data_mem(&data);
+ ntmp_unlock_cbdr(cbdr);
return err;
}
@@ -414,8 +454,9 @@ EXPORT_SYMBOL_GPL(ntmp_rsst_update_entry);
int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count)
{
- struct ntmp_dma_buf data = {.dev = user->dev};
struct ntmp_req_by_eid *req;
+ struct netc_swcbd swcbd;
+ struct netc_cbdr *cbdr;
union netc_cbd cbd;
int err, i;
u8 *group;
@@ -424,21 +465,23 @@ int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count)
/* HW only takes in a full 64 entry table */
return -EINVAL;
- data.size = NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count) +
- RSST_CFGE_DATA_SIZE(count);
- err = ntmp_alloc_data_mem(&data, (void **)&req);
+ swcbd.size = NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count) +
+ RSST_CFGE_DATA_SIZE(count);
+ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
/* Set the request data buffer */
ntmp_fill_crd_eid(req, user->tbl.rsst_ver, 0, 0, 0);
- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(sizeof(*req), data.size),
+ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(sizeof(*req), swcbd.size),
NTMP_RSST_ID, NTMP_CMD_QUERY, NTMP_AM_ENTRY_ID);
- err = netc_xmit_ntmp_cmd(user, &cbd);
+
+ ntmp_select_and_lock_cbdr(user, &cbdr);
+ err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd);
if (err) {
dev_err(user->dev, "Failed to query RSST entry, err: %pe\n",
ERR_PTR(err));
- goto end;
+ goto unlock_cbdr;
}
group = (u8 *)req;
@@ -446,8 +489,8 @@ int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count)
for (i = 0; i < count; i++)
table[i] = group[i];
-end:
- ntmp_free_data_mem(&data);
+unlock_cbdr:
+ ntmp_unlock_cbdr(cbdr);
return err;
}
diff --git a/drivers/net/ethernet/freescale/enetc/ntmp_private.h b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
index 34394e40fddd..f8dff3ba2c28 100644
--- a/drivers/net/ethernet/freescale/enetc/ntmp_private.h
+++ b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
@@ -12,6 +12,9 @@
#define NTMP_EID_REQ_LEN 8
#define NETC_CBDR_BD_NUM 256
+#define NETC_CBDRCIR_INDEX GENMASK(9, 0)
+#define NETC_CBDRCIR_SBE BIT(31)
+#define NETC_CBDR_CLEAN_WORK 16
union netc_cbd {
struct {
@@ -54,13 +57,6 @@ union netc_cbd {
} resp_hdr; /* NTMP Response Message Header Format */
};
-struct ntmp_dma_buf {
- struct device *dev;
- size_t size;
- void *buf;
- dma_addr_t dma;
-};
-
struct ntmp_cmn_req_data {
__le16 update_act;
u8 dbg_opt;
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 9befdacd6730..7ce0cc8ab8f4 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -7706,6 +7706,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err_register:
if (!(adapter->flags & FLAG_HAS_AMT))
e1000e_release_hw_control(adapter);
+ e1000e_ptp_remove(adapter);
err_eeprom:
if (hw->phy.ops.check_reset_block && !hw->phy.ops.check_reset_block(hw))
e1000_phy_hw_reset(&adapter->hw);
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index dcb50c2e1aa2..83e780919ac9 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -1318,6 +1318,7 @@ void i40e_ptp_restore_hw_time(struct i40e_pf *pf);
void i40e_ptp_init(struct i40e_pf *pf);
void i40e_ptp_stop(struct i40e_pf *pf);
int i40e_ptp_alloc_pins(struct i40e_pf *pf);
+void i40e_ptp_free_pins(struct i40e_pf *pf);
int i40e_update_adq_vsi_queues(struct i40e_vsi *vsi, int vsi_offset);
int i40e_is_vsi_uplink_mode_veb(struct i40e_vsi *vsi);
int i40e_get_partition_bw_setting(struct i40e_pf *pf);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 926d001b2150..807ccbbf0182 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -13783,7 +13783,6 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
netdev->neigh_priv_len = sizeof(u32) * 4;
netdev->priv_flags |= IFF_UNICAST_FLT;
- netdev->priv_flags |= IFF_SUPP_NOFCS;
/* Setup netdev TC information */
i40e_vsi_config_netdev_tc(vsi, vsi->tc_config.enabled_tc);
@@ -16112,6 +16111,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
i40e_clear_interrupt_scheme(pf);
kfree(pf->vsi);
err_switch_setup:
+ i40e_ptp_free_pins(pf);
i40e_reset_interrupt_capability(pf);
timer_shutdown_sync(&pf->service_timer);
err_mac_addr:
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
index 404a716db8da..7d07c389bb23 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
@@ -940,12 +940,13 @@ int i40e_ptp_hwtstamp_get(struct net_device *netdev,
*
* Release memory allocated for PTP pins.
**/
-static void i40e_ptp_free_pins(struct i40e_pf *pf)
+void i40e_ptp_free_pins(struct i40e_pf *pf)
{
if (i40e_is_ptp_pin_dev(&pf->hw)) {
kfree(pf->ptp_pins);
kfree(pf->ptp_caps.pin_config);
pf->ptp_pins = NULL;
+ pf->ptp_caps.pin_config = NULL;
}
}
diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h
index e9fb0a0919e3..050f8241ef5e 100644
--- a/drivers/net/ethernet/intel/iavf/iavf.h
+++ b/drivers/net/ethernet/intel/iavf/iavf.h
@@ -158,11 +158,10 @@ struct iavf_vlan {
enum iavf_vlan_state_t {
IAVF_VLAN_INVALID,
IAVF_VLAN_ADD, /* filter needs to be added */
- IAVF_VLAN_IS_NEW, /* filter is new, wait for PF answer */
- IAVF_VLAN_ACTIVE, /* filter is accepted by PF */
- IAVF_VLAN_DISABLE, /* filter needs to be deleted by PF, then marked INACTIVE */
- IAVF_VLAN_INACTIVE, /* filter is inactive, we are in IFF_DOWN */
- IAVF_VLAN_REMOVE, /* filter needs to be removed from list */
+ IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */
+ IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */
+ IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */
+ IAVF_VLAN_REMOVING, /* DEL sent to PF, waiting for response */
};
struct iavf_vlan_filter {
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index dad001abc908..d373feee4c7e 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -757,10 +757,10 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter,
adapter->num_vlan_filters++;
iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER);
} else if (f->state == IAVF_VLAN_REMOVE) {
- /* Re-add the filter since we cannot tell whether the
- * pending delete has already been processed by the PF.
- * A duplicate add is harmless.
- */
+ /* DEL not yet sent to PF, cancel it */
+ f->state = IAVF_VLAN_ACTIVE;
+ } else if (f->state == IAVF_VLAN_REMOVING) {
+ /* DEL already sent to PF, re-add after completion */
f->state = IAVF_VLAN_ADD;
iavf_schedule_aq_request(adapter,
IAVF_FLAG_AQ_ADD_VLAN_FILTER);
@@ -791,37 +791,19 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan)
list_del(&f->list);
kfree(f);
adapter->num_vlan_filters--;
- } else {
+ } else if (f->state != IAVF_VLAN_REMOVING) {
f->state = IAVF_VLAN_REMOVE;
iavf_schedule_aq_request(adapter,
IAVF_FLAG_AQ_DEL_VLAN_FILTER);
}
+ /* If REMOVING, DEL is already sent to PF; completion
+ * handler will free the filter when PF confirms.
+ */
}
spin_unlock_bh(&adapter->mac_vlan_list_lock);
}
-/**
- * iavf_restore_filters
- * @adapter: board private structure
- *
- * Restore existing non MAC filters when VF netdev comes back up
- **/
-static void iavf_restore_filters(struct iavf_adapter *adapter)
-{
- struct iavf_vlan_filter *f;
-
- /* re-add all VLAN filters */
- spin_lock_bh(&adapter->mac_vlan_list_lock);
-
- list_for_each_entry(f, &adapter->vlan_filter_list, list) {
- if (f->state == IAVF_VLAN_INACTIVE)
- f->state = IAVF_VLAN_ADD;
- }
-
- spin_unlock_bh(&adapter->mac_vlan_list_lock);
- adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER;
-}
/**
* iavf_get_num_vlans_added - get number of VLANs added
@@ -1240,13 +1222,12 @@ static void iavf_up_complete(struct iavf_adapter *adapter)
}
/**
- * iavf_clear_mac_vlan_filters - Remove mac and vlan filters not sent to PF
- * yet and mark other to be removed.
+ * iavf_clear_mac_filters - Remove MAC filters not sent to PF yet and mark
+ * others to be removed.
* @adapter: board private structure
**/
-static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter)
+static void iavf_clear_mac_filters(struct iavf_adapter *adapter)
{
- struct iavf_vlan_filter *vlf, *vlftmp;
struct iavf_mac_filter *f, *ftmp;
spin_lock_bh(&adapter->mac_vlan_list_lock);
@@ -1265,11 +1246,6 @@ static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter)
}
}
- /* disable all VLAN filters */
- list_for_each_entry_safe(vlf, vlftmp, &adapter->vlan_filter_list,
- list)
- vlf->state = IAVF_VLAN_DISABLE;
-
spin_unlock_bh(&adapter->mac_vlan_list_lock);
}
@@ -1365,7 +1341,7 @@ void iavf_down(struct iavf_adapter *adapter)
iavf_napi_disable_all(adapter);
iavf_irq_disable(adapter);
- iavf_clear_mac_vlan_filters(adapter);
+ iavf_clear_mac_filters(adapter);
iavf_clear_cloud_filters(adapter);
iavf_clear_fdir_filters(adapter);
iavf_clear_adv_rss_conf(adapter);
@@ -1382,8 +1358,6 @@ void iavf_down(struct iavf_adapter *adapter)
*/
if (!list_empty(&adapter->mac_filter_list))
adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER;
- if (!list_empty(&adapter->vlan_filter_list))
- adapter->aq_required |= IAVF_FLAG_AQ_DEL_VLAN_FILTER;
if (!list_empty(&adapter->cloud_filter_list))
adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER;
if (!list_empty(&adapter->fdir_list_head))
@@ -4488,8 +4462,6 @@ static int iavf_open(struct net_device *netdev)
iavf_add_filter(adapter, adapter->hw.mac.addr);
spin_unlock_bh(&adapter->mac_vlan_list_lock);
- /* Restore filters that were removed with IFF_DOWN */
- iavf_restore_filters(adapter);
iavf_restore_fdir_filters(adapter);
iavf_configure(adapter);
diff --git a/drivers/net/ethernet/intel/iavf/iavf_type.h b/drivers/net/ethernet/intel/iavf/iavf_type.h
index 1d8cf29cb65a..5bb1de1cfd33 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_type.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_type.h
@@ -277,7 +277,7 @@ struct iavf_rx_desc {
/* L2 Tag 2 Presence */
#define IAVF_RXD_LEGACY_L2TAG2P_M BIT(0)
/* Stripped S-TAG VLAN from the receive packet */
-#define IAVF_RXD_LEGACY_L2TAG2_M GENMASK_ULL(63, 32)
+#define IAVF_RXD_LEGACY_L2TAG2_M GENMASK_ULL(63, 48)
/* Stripped S-TAG VLAN from the receive packet */
#define IAVF_RXD_FLEX_L2TAG2_2_M GENMASK_ULL(63, 48)
/* The packet is a UDP tunneled packet */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
index a52c100dcbc5..4f2defd2331b 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -746,7 +746,7 @@ static void iavf_vlan_add_reject(struct iavf_adapter *adapter)
spin_lock_bh(&adapter->mac_vlan_list_lock);
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
- if (f->state == IAVF_VLAN_IS_NEW) {
+ if (f->state == IAVF_VLAN_ADDING) {
list_del(&f->list);
kfree(f);
adapter->num_vlan_filters--;
@@ -812,7 +812,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
if (f->state == IAVF_VLAN_ADD) {
vvfl->vlan_id[i] = f->vlan.vid;
i++;
- f->state = IAVF_VLAN_IS_NEW;
+ f->state = IAVF_VLAN_ADDING;
if (i == count)
break;
}
@@ -874,7 +874,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
vlan->tpid = f->vlan.tpid;
i++;
- f->state = IAVF_VLAN_IS_NEW;
+ f->state = IAVF_VLAN_ADDING;
}
}
@@ -911,22 +911,12 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
spin_lock_bh(&adapter->mac_vlan_list_lock);
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
- /* since VLAN capabilities are not allowed, we dont want to send
- * a VLAN delete request because it will most likely fail and
- * create unnecessary errors/noise, so just free the VLAN
- * filters marked for removal to enable bailing out before
- * sending a virtchnl message
- */
if (f->state == IAVF_VLAN_REMOVE &&
!VLAN_FILTERING_ALLOWED(adapter)) {
list_del(&f->list);
kfree(f);
adapter->num_vlan_filters--;
- } else if (f->state == IAVF_VLAN_DISABLE &&
- !VLAN_FILTERING_ALLOWED(adapter)) {
- f->state = IAVF_VLAN_INACTIVE;
- } else if (f->state == IAVF_VLAN_REMOVE ||
- f->state == IAVF_VLAN_DISABLE) {
+ } else if (f->state == IAVF_VLAN_REMOVE) {
count++;
}
}
@@ -958,18 +948,10 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
vvfl->vsi_id = adapter->vsi_res->vsi_id;
vvfl->num_elements = count;
- list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
- if (f->state == IAVF_VLAN_DISABLE) {
- vvfl->vlan_id[i] = f->vlan.vid;
- f->state = IAVF_VLAN_INACTIVE;
- i++;
- if (i == count)
- break;
- } else if (f->state == IAVF_VLAN_REMOVE) {
+ list_for_each_entry(f, &adapter->vlan_filter_list, list) {
+ if (f->state == IAVF_VLAN_REMOVE) {
vvfl->vlan_id[i] = f->vlan.vid;
- list_del(&f->list);
- kfree(f);
- adapter->num_vlan_filters--;
+ f->state = IAVF_VLAN_REMOVING;
i++;
if (i == count)
break;
@@ -1006,9 +988,8 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
vvfl_v2->vport_id = adapter->vsi_res->vsi_id;
vvfl_v2->num_elements = count;
- list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
- if (f->state == IAVF_VLAN_DISABLE ||
- f->state == IAVF_VLAN_REMOVE) {
+ list_for_each_entry(f, &adapter->vlan_filter_list, list) {
+ if (f->state == IAVF_VLAN_REMOVE) {
struct virtchnl_vlan_supported_caps *filtering_support =
&adapter->vlan_v2_caps.filtering.filtering_support;
struct virtchnl_vlan *vlan;
@@ -1022,13 +1003,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
vlan->tci = f->vlan.vid;
vlan->tpid = f->vlan.tpid;
- if (f->state == IAVF_VLAN_DISABLE) {
- f->state = IAVF_VLAN_INACTIVE;
- } else {
- list_del(&f->list);
- kfree(f);
- adapter->num_vlan_filters--;
- }
+ f->state = IAVF_VLAN_REMOVING;
i++;
if (i == count)
break;
@@ -2391,10 +2366,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
wake_up(&adapter->vc_waitqueue);
break;
- case VIRTCHNL_OP_DEL_VLAN:
- dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n",
- iavf_stat_str(&adapter->hw, v_retval));
- break;
case VIRTCHNL_OP_DEL_ETH_ADDR:
dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n",
iavf_stat_str(&adapter->hw, v_retval));
@@ -2905,17 +2876,42 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
spin_unlock_bh(&adapter->adv_rss_lock);
}
break;
+ case VIRTCHNL_OP_ADD_VLAN:
case VIRTCHNL_OP_ADD_VLAN_V2: {
struct iavf_vlan_filter *f;
+ if (v_retval)
+ break;
+
spin_lock_bh(&adapter->mac_vlan_list_lock);
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
- if (f->state == IAVF_VLAN_IS_NEW)
+ if (f->state == IAVF_VLAN_ADDING)
f->state = IAVF_VLAN_ACTIVE;
}
spin_unlock_bh(&adapter->mac_vlan_list_lock);
}
break;
+ case VIRTCHNL_OP_DEL_VLAN:
+ case VIRTCHNL_OP_DEL_VLAN_V2: {
+ struct iavf_vlan_filter *f, *ftmp;
+
+ spin_lock_bh(&adapter->mac_vlan_list_lock);
+ list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list,
+ list) {
+ if (f->state == IAVF_VLAN_REMOVING) {
+ if (v_retval) {
+ /* PF rejected DEL, keep filter */
+ f->state = IAVF_VLAN_ACTIVE;
+ } else {
+ list_del(&f->list);
+ kfree(f);
+ adapter->num_vlan_filters--;
+ }
+ }
+ }
+ spin_unlock_bh(&adapter->mac_vlan_list_lock);
+ }
+ break;
case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING:
/* PF enabled vlan strip on this VF.
* Update netdev->features if needed to be in sync with ethtool.
diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink.c b/drivers/net/ethernet/intel/ice/devlink/devlink.c
index 6144cee8034d..641d6e289d5c 100644
--- a/drivers/net/ethernet/intel/ice/devlink/devlink.c
+++ b/drivers/net/ethernet/intel/ice/devlink/devlink.c
@@ -1245,6 +1245,8 @@ static int ice_devlink_reinit_up(struct ice_pf *pf)
return err;
}
+ ice_init_dev_hw(pf);
+
/* load MSI-X values */
ice_set_min_max_msix(pf);
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index eb3a48330cc1..725b130dd3a2 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -753,7 +753,7 @@ static inline bool ice_is_xdp_ena_vsi(struct ice_vsi *vsi)
static inline void ice_set_ring_xdp(struct ice_tx_ring *ring)
{
- ring->flags |= ICE_TX_FLAGS_RING_XDP;
+ set_bit(ICE_TX_RING_FLAGS_XDP, ring->flags);
}
/**
@@ -778,7 +778,7 @@ static inline bool ice_is_txtime_ena(const struct ice_tx_ring *ring)
*/
static inline bool ice_is_txtime_cfg(const struct ice_tx_ring *ring)
{
- return !!(ring->flags & ICE_TX_FLAGS_TXTIME);
+ return test_bit(ICE_TX_RING_FLAGS_TXTIME, ring->flags);
}
/**
diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
index 859e9c66f3e7..3cbb1b0582e3 100644
--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
@@ -1252,7 +1252,7 @@ struct ice_aqc_get_link_status_data {
#define ICE_AQ_LINK_PWR_QSFP_CLASS_3 2
#define ICE_AQ_LINK_PWR_QSFP_CLASS_4 3
__le16 link_speed;
-#define ICE_AQ_LINK_SPEED_M 0x7FF
+#define ICE_AQ_LINK_SPEED_M GENMASK(11, 0)
#define ICE_AQ_LINK_SPEED_10MB BIT(0)
#define ICE_AQ_LINK_SPEED_100MB BIT(1)
#define ICE_AQ_LINK_SPEED_1000MB BIT(2)
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index ce11fea122d0..b617a6bff891 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -1126,8 +1126,6 @@ int ice_init_hw(struct ice_hw *hw)
if (status)
goto err_unroll_fltr_mgmt_struct;
- ice_init_dev_hw(hw->back);
-
mutex_init(&hw->tnl_lock);
ice_init_chk_recipe_reuse_support(hw);
diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c
index bd77f1c001ee..16aa25535152 100644
--- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c
@@ -943,7 +943,7 @@ ice_tx_prepare_vlan_flags_dcb(struct ice_tx_ring *tx_ring,
/* if this is not already set it means a VLAN 0 + priority needs
* to be offloaded
*/
- if (tx_ring->flags & ICE_TX_FLAGS_RING_VLAN_L2TAG2)
+ if (test_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG2, tx_ring->flags))
first->tx_flags |= ICE_TX_FLAGS_HW_OUTER_SINGLE_VLAN;
else
first->tx_flags |= ICE_TX_FLAGS_HW_VLAN;
diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c
index 62f75701d652..27b460926bac 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.c
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.c
@@ -1154,6 +1154,32 @@ ice_dpll_input_state_get(const struct dpll_pin *pin, void *pin_priv,
extack, ICE_DPLL_PIN_TYPE_INPUT);
}
+/**
+ * ice_dpll_sw_pin_notify_peer - notify the paired SW pin after a state change
+ * @d: pointer to dplls struct
+ * @changed: the SW pin that was explicitly changed (already notified by dpll core)
+ *
+ * SMA and U.FL pins share physical signal paths in pairs (SMA1/U.FL1 and
+ * SMA2/U.FL2). When one pin's routing changes via the PCA9575 GPIO
+ * expander, the paired pin's state may also change. Send a change
+ * notification for the peer pin so userspace consumers monitoring the
+ * peer via dpll netlink learn about the update.
+ *
+ * Context: Called from dpll_pin_ops callbacks after pf->dplls.lock is
+ * released. Uses __dpll_pin_change_ntf() because dpll_lock is
+ * still held by the dpll netlink layer.
+ */
+static void ice_dpll_sw_pin_notify_peer(struct ice_dplls *d,
+ struct ice_dpll_pin *changed)
+{
+ struct ice_dpll_pin *peer;
+
+ peer = (changed >= d->sma && changed < d->sma + ICE_DPLL_PIN_SW_NUM) ?
+ &d->ufl[changed->idx] : &d->sma[changed->idx];
+ if (peer->pin)
+ __dpll_pin_change_ntf(peer->pin);
+}
+
/**
* ice_dpll_sma_direction_set - set direction of SMA pin
* @p: pointer to a pin
@@ -1171,6 +1197,8 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p,
enum dpll_pin_direction direction,
struct netlink_ext_ack *extack)
{
+ struct ice_dplls *d = &p->pf->dplls;
+ struct ice_dpll_pin *peer;
u8 data;
int ret;
@@ -1189,8 +1217,9 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p,
case ICE_DPLL_PIN_SW_2_IDX:
if (direction == DPLL_PIN_DIRECTION_INPUT) {
data &= ~ICE_SMA2_DIR_EN;
+ data |= ICE_SMA2_UFL2_RX_DIS;
} else {
- data &= ~ICE_SMA2_TX_EN;
+ data &= ~(ICE_SMA2_TX_EN | ICE_SMA2_UFL2_RX_DIS);
data |= ICE_SMA2_DIR_EN;
}
break;
@@ -1202,6 +1231,34 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p,
ret = ice_dpll_pin_state_update(p->pf, p,
ICE_DPLL_PIN_TYPE_SOFTWARE,
extack);
+ if (ret)
+ return ret;
+
+ /* When a direction change activates the paired U.FL pin, enable
+ * its backing CGU pin so the pin reports as connected. Without
+ * this the U.FL routing is correct but the CGU pin stays disabled
+ * and userspace sees the pin as disconnected. Do not disable the
+ * backing pin when U.FL becomes inactive because the SMA pin may
+ * still be using it.
+ */
+ peer = &d->ufl[p->idx];
+ if (peer->active) {
+ struct ice_dpll_pin *target;
+ enum ice_dpll_pin_type type;
+
+ if (peer->output) {
+ target = peer->output;
+ type = ICE_DPLL_PIN_TYPE_OUTPUT;
+ } else {
+ target = peer->input;
+ type = ICE_DPLL_PIN_TYPE_INPUT;
+ }
+ ret = ice_dpll_pin_enable(&p->pf->hw, target,
+ d->eec.dpll_idx, type, extack);
+ if (!ret)
+ ret = ice_dpll_pin_state_update(p->pf, target,
+ type, extack);
+ }
return ret;
}
@@ -1253,6 +1310,14 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv,
data &= ~ICE_SMA1_MASK;
enable = true;
} else if (state == DPLL_PIN_STATE_DISCONNECTED) {
+ /* Skip if U.FL1 is not active, setting TX_EN
+ * while DIR_EN is set would also deactivate
+ * the paired SMA1 output.
+ */
+ if (data & (ICE_SMA1_DIR_EN | ICE_SMA1_TX_EN)) {
+ ret = 0;
+ goto unlock;
+ }
data |= ICE_SMA1_TX_EN;
enable = false;
} else {
@@ -1267,6 +1332,15 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv,
data &= ~ICE_SMA2_UFL2_RX_DIS;
enable = true;
} else if (state == DPLL_PIN_STATE_DISCONNECTED) {
+ /* Skip if U.FL2 is not active, setting
+ * UFL2_RX_DIS could also disable the paired
+ * SMA2 input.
+ */
+ if (!(data & ICE_SMA2_DIR_EN) ||
+ (data & ICE_SMA2_UFL2_RX_DIS)) {
+ ret = 0;
+ goto unlock;
+ }
data |= ICE_SMA2_UFL2_RX_DIS;
enable = false;
} else {
@@ -1296,6 +1370,8 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv,
unlock:
mutex_unlock(&pf->dplls.lock);
+ if (!ret)
+ ice_dpll_sw_pin_notify_peer(&pf->dplls, p);
return ret;
}
@@ -1414,6 +1490,8 @@ ice_dpll_sma_pin_state_set(const struct dpll_pin *pin, void *pin_priv,
unlock:
mutex_unlock(&pf->dplls.lock);
+ if (!ret)
+ ice_dpll_sw_pin_notify_peer(&pf->dplls, sma);
return ret;
}
@@ -1609,6 +1687,8 @@ ice_dpll_pin_sma_direction_set(const struct dpll_pin *pin, void *pin_priv,
mutex_lock(&pf->dplls.lock);
ret = ice_dpll_sma_direction_set(p, direction, extack);
mutex_unlock(&pf->dplls.lock);
+ if (!ret)
+ ice_dpll_sw_pin_notify_peer(&pf->dplls, p);
return ret;
}
@@ -1915,7 +1995,10 @@ ice_dpll_phase_offset_get(const struct dpll_pin *pin, void *pin_priv,
d->active_input == p->input->pin))
*phase_offset = d->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR;
else if (d->phase_offset_monitor_period)
- *phase_offset = p->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR;
+ *phase_offset = (p->input &&
+ p->direction == DPLL_PIN_DIRECTION_INPUT ?
+ p->input->phase_offset :
+ p->phase_offset) * ICE_DPLL_PHASE_OFFSET_FACTOR;
else
*phase_offset = 0;
mutex_unlock(&pf->dplls.lock);
@@ -2609,6 +2692,27 @@ static u64 ice_generate_clock_id(struct ice_pf *pf)
return pci_get_dsn(pf->pdev);
}
+/**
+ * ice_dpll_pin_ntf - notify pin change including any SW pin wrappers
+ * @dplls: pointer to dplls struct
+ * @pin: the dpll_pin that changed
+ *
+ * Send a change notification for @pin and for any registered SMA/U.FL pin
+ * whose backing CGU input matches @pin.
+ */
+static void ice_dpll_pin_ntf(struct ice_dplls *dplls, struct dpll_pin *pin)
+{
+ dpll_pin_change_ntf(pin);
+ for (int i = 0; i < ICE_DPLL_PIN_SW_NUM; i++) {
+ if (dplls->sma[i].pin && dplls->sma[i].input &&
+ dplls->sma[i].input->pin == pin)
+ dpll_pin_change_ntf(dplls->sma[i].pin);
+ if (dplls->ufl[i].pin && dplls->ufl[i].input &&
+ dplls->ufl[i].input->pin == pin)
+ dpll_pin_change_ntf(dplls->ufl[i].pin);
+ }
+}
+
/**
* ice_dpll_notify_changes - notify dpll subsystem about changes
* @d: pointer do dpll
@@ -2617,6 +2721,7 @@ static u64 ice_generate_clock_id(struct ice_pf *pf)
*/
static void ice_dpll_notify_changes(struct ice_dpll *d)
{
+ struct ice_dplls *dplls = &d->pf->dplls;
bool pin_notified = false;
if (d->prev_dpll_state != d->dpll_state) {
@@ -2625,17 +2730,17 @@ static void ice_dpll_notify_changes(struct ice_dpll *d)
}
if (d->prev_input != d->active_input) {
if (d->prev_input)
- dpll_pin_change_ntf(d->prev_input);
+ ice_dpll_pin_ntf(dplls, d->prev_input);
d->prev_input = d->active_input;
if (d->active_input) {
- dpll_pin_change_ntf(d->active_input);
+ ice_dpll_pin_ntf(dplls, d->active_input);
pin_notified = true;
}
}
if (d->prev_phase_offset != d->phase_offset) {
d->prev_phase_offset = d->phase_offset;
if (!pin_notified && d->active_input)
- dpll_pin_change_ntf(d->active_input);
+ ice_dpll_pin_ntf(dplls, d->active_input);
}
}
@@ -2664,6 +2769,7 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf)
/**
* ice_dpll_pins_notify_mask - notify dpll subsystem about bulk pin changes
+ * @dplls: pointer to dplls struct
* @pins: array of ice_dpll_pin pointers registered within dpll subsystem
* @pin_num: number of pins
* @phase_offset_ntf_mask: bitmask of pin indexes to notify
@@ -2673,15 +2779,14 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf)
*
* Context: Must be called while pf->dplls.lock is released.
*/
-static void ice_dpll_pins_notify_mask(struct ice_dpll_pin *pins,
+static void ice_dpll_pins_notify_mask(struct ice_dplls *dplls,
+ struct ice_dpll_pin *pins,
u8 pin_num,
u32 phase_offset_ntf_mask)
{
- int i = 0;
-
- for (i = 0; i < pin_num; i++)
- if (phase_offset_ntf_mask & (1 << i))
- dpll_pin_change_ntf(pins[i].pin);
+ for (int i = 0; i < pin_num; i++)
+ if (phase_offset_ntf_mask & BIT(i))
+ ice_dpll_pin_ntf(dplls, pins[i].pin);
}
/**
@@ -2857,7 +2962,7 @@ static void ice_dpll_periodic_work(struct kthread_work *work)
ice_dpll_notify_changes(de);
ice_dpll_notify_changes(dp);
if (phase_offset_ntf)
- ice_dpll_pins_notify_mask(d->inputs, d->num_inputs,
+ ice_dpll_pins_notify_mask(d, d->inputs, d->num_inputs,
phase_offset_ntf);
resched:
@@ -4014,6 +4119,7 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf)
struct ice_dpll_pin *pin;
u32 phase_adj_max, caps;
int i, ret;
+ u8 data;
if (pf->hw.device_id == ICE_DEV_ID_E810C_QSFP)
input_idx_offset = ICE_E810_RCLK_PINS_NUM;
@@ -4073,6 +4179,22 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf)
}
ice_dpll_phase_range_set(&pin->prop.phase_range, phase_adj_max);
}
+
+ /* Initialize the SMA control register to a known-good default state.
+ * Without this write the PCA9575 GPIO expander retains its power-on
+ * default (all outputs high) which makes all SW pins appear inactive.
+ * Set SMA1 and SMA2 as active inputs, disable U.FL1 output and
+ * U.FL2 input.
+ */
+ ret = ice_read_sma_ctrl(&pf->hw, &data);
+ if (ret)
+ return ret;
+ data &= ~ICE_ALL_SMA_MASK;
+ data |= ICE_SMA1_TX_EN | ICE_SMA2_TX_EN | ICE_SMA2_UFL2_RX_DIS;
+ ret = ice_write_sma_ctrl(&pf->hw, data);
+ if (ret)
+ return ret;
+
ret = ice_dpll_pin_state_update(pf, pin, ICE_DPLL_PIN_TYPE_SOFTWARE,
NULL);
if (ret)
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index e6a20af6f63d..f28416a707d7 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -3290,6 +3290,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,
tx_rings[i].desc = NULL;
tx_rings[i].tx_buf = NULL;
tx_rings[i].tstamp_ring = NULL;
+ clear_bit(ICE_TX_RING_FLAGS_TXTIME, tx_rings[i].flags);
tx_rings[i].tx_tstamps = &pf->ptp.port.tx;
err = ice_setup_tx_ring(&tx_rings[i]);
if (err) {
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 689c6025ea82..837b71b7b2b7 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -1412,9 +1412,9 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi)
ring->count = vsi->num_tx_desc;
ring->txq_teid = ICE_INVAL_TEID;
if (dvm_ena)
- ring->flags |= ICE_TX_FLAGS_RING_VLAN_L2TAG2;
+ set_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG2, ring->flags);
else
- ring->flags |= ICE_TX_FLAGS_RING_VLAN_L2TAG1;
+ set_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG1, ring->flags);
WRITE_ONCE(vsi->tx_rings[i], ring);
}
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 3c36e3641b9e..055968485af6 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -1922,82 +1922,6 @@ static void ice_handle_mdd_event(struct ice_pf *pf)
ice_print_vfs_mdd_events(pf);
}
-/**
- * ice_force_phys_link_state - Force the physical link state
- * @vsi: VSI to force the physical link state to up/down
- * @link_up: true/false indicates to set the physical link to up/down
- *
- * Force the physical link state by getting the current PHY capabilities from
- * hardware and setting the PHY config based on the determined capabilities. If
- * link changes a link event will be triggered because both the Enable Automatic
- * Link Update and LESM Enable bits are set when setting the PHY capabilities.
- *
- * Returns 0 on success, negative on failure
- */
-static int ice_force_phys_link_state(struct ice_vsi *vsi, bool link_up)
-{
- struct ice_aqc_get_phy_caps_data *pcaps;
- struct ice_aqc_set_phy_cfg_data *cfg;
- struct ice_port_info *pi;
- struct device *dev;
- int retcode;
-
- if (!vsi || !vsi->port_info || !vsi->back)
- return -EINVAL;
- if (vsi->type != ICE_VSI_PF)
- return 0;
-
- dev = ice_pf_to_dev(vsi->back);
-
- pi = vsi->port_info;
-
- pcaps = kzalloc_obj(*pcaps);
- if (!pcaps)
- return -ENOMEM;
-
- retcode = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_ACTIVE_CFG, pcaps,
- NULL);
- if (retcode) {
- dev_err(dev, "Failed to get phy capabilities, VSI %d error %d\n",
- vsi->vsi_num, retcode);
- retcode = -EIO;
- goto out;
- }
-
- /* No change in link */
- if (link_up == !!(pcaps->caps & ICE_AQC_PHY_EN_LINK) &&
- link_up == !!(pi->phy.link_info.link_info & ICE_AQ_LINK_UP))
- goto out;
-
- /* Use the current user PHY configuration. The current user PHY
- * configuration is initialized during probe from PHY capabilities
- * software mode, and updated on set PHY configuration.
- */
- cfg = kmemdup(&pi->phy.curr_user_phy_cfg, sizeof(*cfg), GFP_KERNEL);
- if (!cfg) {
- retcode = -ENOMEM;
- goto out;
- }
-
- cfg->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
- if (link_up)
- cfg->caps |= ICE_AQ_PHY_ENA_LINK;
- else
- cfg->caps &= ~ICE_AQ_PHY_ENA_LINK;
-
- retcode = ice_aq_set_phy_cfg(&vsi->back->hw, pi, cfg, NULL);
- if (retcode) {
- dev_err(dev, "Failed to set phy config, VSI %d error %d\n",
- vsi->vsi_num, retcode);
- retcode = -EIO;
- }
-
- kfree(cfg);
-out:
- kfree(pcaps);
- return retcode;
-}
-
/**
* ice_init_nvm_phy_type - Initialize the NVM PHY type
* @pi: port info structure
@@ -2066,7 +1990,7 @@ static void ice_init_link_dflt_override(struct ice_port_info *pi)
* first time media is available. The ICE_LINK_DEFAULT_OVERRIDE_PENDING state
* is used to indicate that the user PHY cfg default override is initialized
* and the PHY has not been configured with the default override settings. The
- * state is set here, and cleared in ice_configure_phy the first time the PHY is
+ * state is set here, and cleared in ice_phy_cfg the first time the PHY is
* configured.
*
* This function should be called only if the FW doesn't support default
@@ -2172,14 +2096,18 @@ static int ice_init_phy_user_cfg(struct ice_port_info *pi)
}
/**
- * ice_configure_phy - configure PHY
+ * ice_phy_cfg - configure PHY
* @vsi: VSI of PHY
+ * @link_en: true/false indicates to set link to enable/disable
*
* Set the PHY configuration. If the current PHY configuration is the same as
- * the curr_user_phy_cfg, then do nothing to avoid link flap. Otherwise
- * configure the based get PHY capabilities for topology with media.
+ * the curr_user_phy_cfg and link_en hasn't changed, then do nothing to avoid
+ * link flap. Otherwise configure the PHY based get PHY capabilities for
+ * topology with media and link_en.
+ *
+ * Return: 0 on success, negative on failure
*/
-static int ice_configure_phy(struct ice_vsi *vsi)
+static int ice_phy_cfg(struct ice_vsi *vsi, bool link_en)
{
struct device *dev = ice_pf_to_dev(vsi->back);
struct ice_port_info *pi = vsi->port_info;
@@ -2199,9 +2127,6 @@ static int ice_configure_phy(struct ice_vsi *vsi)
phy->link_info.topo_media_conflict == ICE_AQ_LINK_TOPO_UNSUPP_MEDIA)
return -EPERM;
- if (test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags))
- return ice_force_phys_link_state(vsi, true);
-
pcaps = kzalloc_obj(*pcaps);
if (!pcaps)
return -ENOMEM;
@@ -2215,10 +2140,8 @@ static int ice_configure_phy(struct ice_vsi *vsi)
goto done;
}
- /* If PHY enable link is configured and configuration has not changed,
- * there's nothing to do
- */
- if (pcaps->caps & ICE_AQC_PHY_EN_LINK &&
+ /* Configuration has not changed. There's nothing to do. */
+ if (link_en == !!(pcaps->caps & ICE_AQC_PHY_EN_LINK) &&
ice_phy_caps_equals_cfg(pcaps, &phy->curr_user_phy_cfg))
goto done;
@@ -2282,8 +2205,12 @@ static int ice_configure_phy(struct ice_vsi *vsi)
*/
ice_cfg_phy_fc(pi, cfg, phy->curr_user_fc_req);
- /* Enable link and link update */
- cfg->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT | ICE_AQ_PHY_ENA_LINK;
+ /* Enable/Disable link and link update */
+ cfg->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
+ if (link_en)
+ cfg->caps |= ICE_AQ_PHY_ENA_LINK;
+ else
+ cfg->caps &= ~ICE_AQ_PHY_ENA_LINK;
err = ice_aq_set_phy_cfg(&pf->hw, pi, cfg, NULL);
if (err)
@@ -2336,7 +2263,7 @@ static void ice_check_media_subtask(struct ice_pf *pf)
test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags))
return;
- err = ice_configure_phy(vsi);
+ err = ice_phy_cfg(vsi, true);
if (!err)
clear_bit(ICE_FLAG_NO_MEDIA, pf->flags);
@@ -4892,9 +4819,15 @@ static int ice_init_link(struct ice_pf *pf)
if (!test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags)) {
struct ice_vsi *vsi = ice_get_main_vsi(pf);
+ struct ice_link_default_override_tlv *ldo;
+ bool link_en;
+
+ ldo = &pf->link_dflt_override;
+ link_en = !(ldo->options &
+ ICE_LINK_OVERRIDE_AUTO_LINK_DIS);
if (vsi)
- ice_configure_phy(vsi);
+ ice_phy_cfg(vsi, link_en);
}
} else {
set_bit(ICE_FLAG_NO_MEDIA, pf->flags);
@@ -5312,6 +5245,8 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
return err;
}
+ ice_init_dev_hw(pf);
+
adapter = ice_adapter_get(pdev);
if (IS_ERR(adapter)) {
err = PTR_ERR(adapter);
@@ -9707,7 +9642,7 @@ int ice_open_internal(struct net_device *netdev)
}
}
- err = ice_configure_phy(vsi);
+ err = ice_phy_cfg(vsi, true);
if (err) {
netdev_err(netdev, "Failed to set physical link up, error %d\n",
err);
@@ -9748,7 +9683,7 @@ int ice_stop(struct net_device *netdev)
}
if (test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags)) {
- int link_err = ice_force_phys_link_state(vsi, false);
+ int link_err = ice_phy_cfg(vsi, false);
if (link_err) {
if (link_err == -ENOMEDIUM)
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
index 6cb0cf7a9891..36df742c326c 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -2710,7 +2710,7 @@ static bool ice_any_port_has_timestamps(struct ice_pf *pf)
bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf)
{
struct ice_hw *hw = &pf->hw;
- unsigned int i;
+ int ret;
/* Check software indicator */
switch (pf->ptp.tx_interrupt_mode) {
@@ -2731,16 +2731,19 @@ bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf)
}
/* Check hardware indicator */
- for (i = 0; i < ICE_GET_QUAD_NUM(hw->ptp.num_lports); i++) {
- u64 tstamp_ready = 0;
- int err;
-
- err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready);
- if (err || tstamp_ready)
- return true;
+ ret = ice_check_phy_tx_tstamp_ready(hw);
+ if (ret < 0) {
+ dev_dbg(ice_pf_to_dev(pf), "Unable to read PHY Tx timestamp ready bitmap, err %d\n",
+ ret);
+ /* Stop triggering IRQs if we're unable to read PHY */
+ return false;
}
- return false;
+ /* ice_check_phy_tx_tstamp_ready() returns 1 if there are timestamps
+ * available, 0 if there are no waiting timestamps, and a negative
+ * value if there was an error (which we checked for above).
+ */
+ return ret > 0;
}
/**
@@ -2824,8 +2827,7 @@ static void ice_ptp_maybe_trigger_tx_interrupt(struct ice_pf *pf)
{
struct device *dev = ice_pf_to_dev(pf);
struct ice_hw *hw = &pf->hw;
- bool trigger_oicr = false;
- unsigned int i;
+ int ret;
if (!pf->ptp.port.tx.has_ready_bitmap)
return;
@@ -2833,21 +2835,11 @@ static void ice_ptp_maybe_trigger_tx_interrupt(struct ice_pf *pf)
if (!ice_pf_src_tmr_owned(pf))
return;
- for (i = 0; i < ICE_GET_QUAD_NUM(hw->ptp.num_lports); i++) {
- u64 tstamp_ready;
- int err;
-
- err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready);
- if (!err && tstamp_ready) {
- trigger_oicr = true;
- break;
- }
- }
-
- if (trigger_oicr) {
- /* Trigger a software interrupt, to ensure this data
- * gets processed.
- */
+ ret = ice_check_phy_tx_tstamp_ready(hw);
+ if (ret < 0) {
+ dev_dbg(dev, "PTP periodic task unable to read PHY timestamp ready bitmap, err %d\n",
+ ret);
+ } else if (ret) {
dev_dbg(dev, "PTP periodic task detected waiting timestamps. Triggering Tx timestamp interrupt now.\n");
wr32(hw, PFINT_OICR, PFINT_OICR_TSYN_TX_M);
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_consts.h b/drivers/net/ethernet/intel/ice/ice_ptp_consts.h
index 19dddd9b53dd..4d298c27bfb2 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_consts.h
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_consts.h
@@ -78,14 +78,14 @@ struct ice_eth56g_mac_reg_cfg eth56g_mac_cfg[NUM_ICE_ETH56G_LNK_SPD] = {
.blktime = 0x666, /* 3.2 */
.tx_offset = {
.serdes = 0x234c, /* 17.6484848 */
- .no_fec = 0x8e80, /* 71.25 */
+ .no_fec = 0x93d9, /* 73 */
.fc = 0xb4a4, /* 90.32 */
.sfd = 0x4a4, /* 2.32 */
.onestep = 0x4ccd /* 38.4 */
},
.rx_offset = {
.serdes = 0xffffeb27, /* -10.42424 */
- .no_fec = 0xffffcccd, /* -25.6 */
+ .no_fec = 0xffffc7b6, /* -28 */
.fc = 0xfffc557b, /* -469.26 */
.sfd = 0x4a4, /* 2.32 */
.bs_ds = 0x32 /* 0.0969697 */
@@ -118,17 +118,17 @@ struct ice_eth56g_mac_reg_cfg eth56g_mac_cfg[NUM_ICE_ETH56G_LNK_SPD] = {
.mktime = 0x147b, /* 10.24, only if RS-FEC enabled */
.tx_offset = {
.serdes = 0xe1e, /* 7.0593939 */
- .no_fec = 0x3857, /* 28.17 */
+ .no_fec = 0x4266, /* 33 */
.fc = 0x48c3, /* 36.38 */
- .rs = 0x8100, /* 64.5 */
+ .rs = 0x8a00, /* 69 */
.sfd = 0x1dc, /* 0.93 */
.onestep = 0x1eb8 /* 15.36 */
},
.rx_offset = {
.serdes = 0xfffff7a9, /* -4.1697 */
- .no_fec = 0xffffe71a, /* -12.45 */
+ .no_fec = 0xffffe700, /* -12 */
.fc = 0xfffe894d, /* -187.35 */
- .rs = 0xfffff8cd, /* -3.6 */
+ .rs = 0xfffff8cc, /* -3 */
.sfd = 0x1dc, /* 0.93 */
.bs_ds = 0x14 /* 0.0387879, RS-FEC 0 */
}
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
index 61c0a0d93ea8..24fb7a3e14d6 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
@@ -377,6 +377,31 @@ static void ice_ptp_cfg_sync_delay(const struct ice_hw *hw, u32 delay)
* The following functions operate on devices with the ETH 56G PHY.
*/
+/**
+ * ice_ptp_init_phc_e825c - Perform E825C specific PHC initialization
+ * @hw: pointer to HW struct
+ *
+ * Perform E825C-specific PTP hardware clock initialization steps.
+ *
+ * Return: 0 on success, or a negative error value on failure.
+ */
+static int ice_ptp_init_phc_e825c(struct ice_hw *hw)
+{
+ int err;
+
+ /* Soft reset all ports, to ensure everything is at a clean state */
+ for (int port = 0; port < hw->ptp.num_lports; port++) {
+ err = ice_ptp_phy_soft_reset_eth56g(hw, port);
+ if (err) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to soft reset port %d, err %d\n",
+ port, err);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
/**
* ice_ptp_get_dest_dev_e825 - get destination PHY for given port number
* @hw: pointer to the HW struct
@@ -1847,6 +1872,8 @@ static int ice_phy_cfg_mac_eth56g(struct ice_hw *hw, u8 port)
* @ena: enable or disable interrupt
* @threshold: interrupt threshold
*
+ * The threshold cannot be 0 while the interrupt is enabled.
+ *
* Configure TX timestamp interrupt for the specified port
*
* Return:
@@ -1858,19 +1885,45 @@ int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold)
int err;
u32 val;
+ if (ena && !threshold)
+ return -EINVAL;
+
err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, &val);
if (err)
return err;
+ val &= ~PHY_TS_INT_CONFIG_ENA_M;
if (ena) {
- val |= PHY_TS_INT_CONFIG_ENA_M;
val &= ~PHY_TS_INT_CONFIG_THRESHOLD_M;
val |= FIELD_PREP(PHY_TS_INT_CONFIG_THRESHOLD_M, threshold);
- } else {
- val &= ~PHY_TS_INT_CONFIG_ENA_M;
+ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG,
+ val);
+ if (err) {
+ ice_debug(hw, ICE_DBG_PTP,
+ "Failed to update 'threshold' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n",
+ port, !!ena, threshold);
+ return err;
+ }
+ val |= PHY_TS_INT_CONFIG_ENA_M;
+ }
+
+ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, val);
+ if (err) {
+ ice_debug(hw, ICE_DBG_PTP,
+ "Failed to update 'ena' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n",
+ port, !!ena, threshold);
+ return err;
}
- return ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, val);
+ err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, &val);
+ if (err) {
+ ice_debug(hw, ICE_DBG_PTP,
+ "Failed to read PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n",
+ port, !!ena, threshold);
+ return err;
+ }
+
+ return 0;
}
/**
@@ -2115,6 +2168,35 @@ int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port)
return 0;
}
+/**
+ * ice_check_phy_tx_tstamp_ready_eth56g - Check Tx memory status for all ports
+ * @hw: pointer to the HW struct
+ *
+ * Check the PHY_REG_TX_MEMORY_STATUS for all ports. A set bit indicates
+ * a waiting timestamp.
+ *
+ * Return: 1 if any port has at least one timestamp ready bit set,
+ * 0 otherwise, and a negative error code if unable to read the bitmap.
+ */
+static int ice_check_phy_tx_tstamp_ready_eth56g(struct ice_hw *hw)
+{
+ int port;
+
+ for (port = 0; port < hw->ptp.num_lports; port++) {
+ u64 tstamp_ready;
+ int err;
+
+ err = ice_get_phy_tx_tstamp_ready(hw, port, &tstamp_ready);
+ if (err)
+ return err;
+
+ if (tstamp_ready)
+ return 1;
+ }
+
+ return 0;
+}
+
/**
* ice_ptp_read_tx_hwtstamp_status_eth56g - Get TX timestamp status
* @hw: pointer to the HW struct
@@ -2137,13 +2219,19 @@ int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status)
*ts_status = 0;
for (phy = 0; phy < params->num_phys; phy++) {
+ u8 port;
int err;
- err = ice_read_phy_eth56g(hw, phy, PHY_PTP_INT_STATUS, &status);
+ /* ice_read_phy_eth56g expects a port index, so use the first
+ * port of the PHY
+ */
+ port = phy * hw->ptp.ports_per_phy;
+
+ err = ice_read_phy_eth56g(hw, port, PHY_PTP_INT_STATUS, &status);
if (err)
return err;
- *ts_status |= (status & mask) << (phy * hw->ptp.ports_per_phy);
+ *ts_status |= (status & mask) << port;
}
ice_debug(hw, ICE_DBG_PTP, "PHY interrupt err: %x\n", *ts_status);
@@ -2151,6 +2239,69 @@ int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status)
return 0;
}
+/**
+ * ice_ptp_phy_soft_reset_eth56g - Perform a PHY soft reset on ETH56G
+ * @hw: pointer to the HW structure
+ * @port: PHY port number
+ *
+ * Trigger a soft reset of the ETH56G PHY by toggling the soft reset
+ * bit in the PHY global register. The reset sequence consists of:
+ * 1. Clearing the soft reset bit
+ * 2. Asserting the soft reset bit
+ * 3. Clearing the soft reset bit again
+ *
+ * Short delays are inserted between each step to allow the hardware
+ * to settle. This provides a controlled way to reinitialize the PHY
+ * without requiring a full device reset.
+ *
+ * Return: 0 on success, or a negative error code on failure when
+ * reading or writing the PHY register.
+ */
+int ice_ptp_phy_soft_reset_eth56g(struct ice_hw *hw, u8 port)
+{
+ u32 global_val;
+ int err;
+
+ err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, &global_val);
+ if (err) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to read PHY_REG_GLOBAL for port %d, err %d\n",
+ port, err);
+ return err;
+ }
+
+ global_val &= ~PHY_REG_GLOBAL_SOFT_RESET_M;
+ ice_debug(hw, ICE_DBG_PTP, "Clearing soft reset bit for port %d, val: 0x%x\n",
+ port, global_val);
+ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val);
+ if (err) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n",
+ port, err);
+ return err;
+ }
+
+ usleep_range(5000, 6000);
+
+ global_val |= PHY_REG_GLOBAL_SOFT_RESET_M;
+ ice_debug(hw, ICE_DBG_PTP, "Set soft reset bit for port %d, val: 0x%x\n",
+ port, global_val);
+ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val);
+ if (err) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n",
+ port, err);
+ return err;
+ }
+ usleep_range(5000, 6000);
+
+ global_val &= ~PHY_REG_GLOBAL_SOFT_RESET_M;
+ ice_debug(hw, ICE_DBG_PTP, "Clear soft reset bit for port %d, val: 0x%x\n",
+ port, global_val);
+ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val);
+ if (err)
+ ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n",
+ port, err);
+ return err;
+}
+
/**
* ice_get_phy_tx_tstamp_ready_eth56g - Read the Tx memory status register
* @hw: pointer to the HW struct
@@ -4202,6 +4353,35 @@ ice_get_phy_tx_tstamp_ready_e82x(struct ice_hw *hw, u8 quad, u64 *tstamp_ready)
return 0;
}
+/**
+ * ice_check_phy_tx_tstamp_ready_e82x - Check Tx memory status for all quads
+ * @hw: pointer to the HW struct
+ *
+ * Check the Q_REG_TX_MEMORY_STATUS for all quads. A set bit indicates
+ * a waiting timestamp.
+ *
+ * Return: 1 if any quad has at least one timestamp ready bit set,
+ * 0 otherwise, and a negative error value if unable to read the bitmap.
+ */
+static int ice_check_phy_tx_tstamp_ready_e82x(struct ice_hw *hw)
+{
+ int quad;
+
+ for (quad = 0; quad < ICE_GET_QUAD_NUM(hw->ptp.num_lports); quad++) {
+ u64 tstamp_ready;
+ int err;
+
+ err = ice_get_phy_tx_tstamp_ready(hw, quad, &tstamp_ready);
+ if (err)
+ return err;
+
+ if (tstamp_ready)
+ return 1;
+ }
+
+ return 0;
+}
+
/**
* ice_phy_cfg_intr_e82x - Configure TX timestamp interrupt
* @hw: pointer to the HW struct
@@ -4755,6 +4935,23 @@ ice_get_phy_tx_tstamp_ready_e810(struct ice_hw *hw, u8 port, u64 *tstamp_ready)
return 0;
}
+/**
+ * ice_check_phy_tx_tstamp_ready_e810 - Check Tx memory status register
+ * @hw: pointer to the HW struct
+ *
+ * The E810 devices do not have a Tx memory status register. Note this is
+ * intentionally different behavior from ice_get_phy_tx_tstamp_ready_e810
+ * which always says that all bits are ready. This function is called in cases
+ * where code will trigger interrupts if timestamps are waiting, and should
+ * not be called for E810 hardware.
+ *
+ * Return: 0.
+ */
+static int ice_check_phy_tx_tstamp_ready_e810(struct ice_hw *hw)
+{
+ return 0;
+}
+
/* E810 SMA functions
*
* The following functions operate specifically on E810 hardware and are used
@@ -5009,6 +5206,21 @@ static void ice_get_phy_tx_tstamp_ready_e830(const struct ice_hw *hw, u8 port,
*tstamp_ready |= rd32(hw, E830_PRTMAC_TS_TX_MEM_VALID_L);
}
+/**
+ * ice_check_phy_tx_tstamp_ready_e830 - Check Tx memory status register
+ * @hw: pointer to the HW struct
+ *
+ * Return: 1 if the device has waiting timestamps, 0 otherwise.
+ */
+static int ice_check_phy_tx_tstamp_ready_e830(struct ice_hw *hw)
+{
+ u64 tstamp_ready;
+
+ ice_get_phy_tx_tstamp_ready_e830(hw, 0, &tstamp_ready);
+
+ return !!tstamp_ready;
+}
+
/**
* ice_ptp_init_phy_e830 - initialize PHY parameters
* @ptp: pointer to the PTP HW struct
@@ -5381,8 +5593,8 @@ int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval)
*/
int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj)
{
+ int err = 0;
u8 tmr_idx;
- int err;
tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
@@ -5399,8 +5611,8 @@ int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj)
err = ice_ptp_prep_phy_adj_e810(hw, adj);
break;
case ICE_MAC_E830:
- /* E830 sync PHYs automatically after setting GLTSYN_SHADJ */
- return 0;
+ /* E830 sync PHYs automatically after setting cmd register */
+ break;
case ICE_MAC_GENERIC:
err = ice_ptp_prep_phy_adj_e82x(hw, adj);
break;
@@ -5564,7 +5776,7 @@ int ice_ptp_init_phc(struct ice_hw *hw)
case ICE_MAC_GENERIC:
return ice_ptp_init_phc_e82x(hw);
case ICE_MAC_GENERIC_3K_E825:
- return 0;
+ return ice_ptp_init_phc_e825c(hw);
default:
return -EOPNOTSUPP;
}
@@ -5601,6 +5813,33 @@ int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready)
}
}
+/**
+ * ice_check_phy_tx_tstamp_ready - Check PHY Tx timestamp memory status
+ * @hw: pointer to the HW struct
+ *
+ * Check the PHY for Tx timestamp memory status on all ports. If you need to
+ * see individual timestamp status for each index, use
+ * ice_get_phy_tx_tstamp_ready() instead.
+ *
+ * Return: 1 if any port has timestamps available, 0 if there are no timestamps
+ * available, and a negative error code on failure.
+ */
+int ice_check_phy_tx_tstamp_ready(struct ice_hw *hw)
+{
+ switch (hw->mac_type) {
+ case ICE_MAC_E810:
+ return ice_check_phy_tx_tstamp_ready_e810(hw);
+ case ICE_MAC_E830:
+ return ice_check_phy_tx_tstamp_ready_e830(hw);
+ case ICE_MAC_GENERIC:
+ return ice_check_phy_tx_tstamp_ready_e82x(hw);
+ case ICE_MAC_GENERIC_3K_E825:
+ return ice_check_phy_tx_tstamp_ready_eth56g(hw);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
/**
* ice_cgu_get_pin_desc_e823 - get pin description array
* @hw: pointer to the hw struct
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
index 5896b346e579..1b58b054f4a5 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
@@ -300,6 +300,7 @@ void ice_ptp_reset_ts_memory(struct ice_hw *hw);
int ice_ptp_init_phc(struct ice_hw *hw);
void ice_ptp_init_hw(struct ice_hw *hw);
int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready);
+int ice_check_phy_tx_tstamp_ready(struct ice_hw *hw);
int ice_ptp_one_port_cmd(struct ice_hw *hw, u8 configured_port,
enum ice_ptp_tmr_cmd configured_cmd);
@@ -374,6 +375,7 @@ int ice_stop_phy_timer_eth56g(struct ice_hw *hw, u8 port, bool soft_reset);
int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port);
int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold);
int ice_phy_cfg_ptp_1step_eth56g(struct ice_hw *hw, u8 port);
+int ice_ptp_phy_soft_reset_eth56g(struct ice_hw *hw, u8 port);
#define ICE_ETH56G_NOMINAL_INCVAL 0x140000000ULL
#define ICE_ETH56G_NOMINAL_PCS_REF_TUS 0x100000000ULL
@@ -676,6 +678,9 @@ static inline u64 ice_get_base_incval(struct ice_hw *hw)
#define ICE_P0_GNSS_PRSNT_N BIT(4)
/* ETH56G PHY register addresses */
+#define PHY_REG_GLOBAL 0x0
+#define PHY_REG_GLOBAL_SOFT_RESET_M BIT(11)
+
/* Timestamp PHY incval registers */
#define PHY_REG_TIMETUS_L 0x8
#define PHY_REG_TIMETUS_U 0xC
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index a2cd4cf37734..4ca1a0602307 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -190,9 +190,10 @@ void ice_free_tstamp_ring(struct ice_tx_ring *tx_ring)
void ice_free_tx_tstamp_ring(struct ice_tx_ring *tx_ring)
{
ice_free_tstamp_ring(tx_ring);
+ clear_bit(ICE_TX_RING_FLAGS_TXTIME, tx_ring->flags);
+ smp_wmb(); /* order flag clear before pointer NULL */
kfree_rcu(tx_ring->tstamp_ring, rcu);
- tx_ring->tstamp_ring = NULL;
- tx_ring->flags &= ~ICE_TX_FLAGS_TXTIME;
+ WRITE_ONCE(tx_ring->tstamp_ring, NULL);
}
/**
@@ -405,7 +406,7 @@ static int ice_alloc_tstamp_ring(struct ice_tx_ring *tx_ring)
tx_ring->tstamp_ring = tstamp_ring;
tstamp_ring->desc = NULL;
tstamp_ring->count = ice_calc_ts_ring_count(tx_ring);
- tx_ring->flags |= ICE_TX_FLAGS_TXTIME;
+ set_bit(ICE_TX_RING_FLAGS_TXTIME, tx_ring->flags);
return 0;
}
@@ -1521,13 +1522,20 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first,
return;
if (ice_is_txtime_cfg(tx_ring)) {
- struct ice_tstamp_ring *tstamp_ring = tx_ring->tstamp_ring;
- u32 tstamp_count = tstamp_ring->count;
- u32 j = tstamp_ring->next_to_use;
+ struct ice_tstamp_ring *tstamp_ring;
+ u32 tstamp_count, j;
struct ice_ts_desc *ts_desc;
struct timespec64 ts;
u32 tstamp;
+ smp_rmb(); /* order flag read before pointer read */
+ tstamp_ring = READ_ONCE(tx_ring->tstamp_ring);
+ if (unlikely(!tstamp_ring))
+ goto ring_kick;
+
+ tstamp_count = tstamp_ring->count;
+ j = tstamp_ring->next_to_use;
+
ts = ktime_to_timespec64(first->skb->tstamp);
tstamp = ts.tv_nsec >> ICE_TXTIME_CTX_RESOLUTION_128NS;
@@ -1555,6 +1563,7 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first,
tstamp_ring->next_to_use = j;
writel_relaxed(j, tstamp_ring->tail);
} else {
+ring_kick:
writel_relaxed(i, tx_ring->tail);
}
return;
@@ -1814,7 +1823,7 @@ ice_tx_prepare_vlan_flags(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first)
*/
if (skb_vlan_tag_present(skb)) {
first->vid = skb_vlan_tag_get(skb);
- if (tx_ring->flags & ICE_TX_FLAGS_RING_VLAN_L2TAG2)
+ if (test_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG2, tx_ring->flags))
first->tx_flags |= ICE_TX_FLAGS_HW_OUTER_SINGLE_VLAN;
else
first->tx_flags |= ICE_TX_FLAGS_HW_VLAN;
@@ -2158,6 +2167,9 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)
ice_trace(xmit_frame_ring, tx_ring, skb);
+ /* record the location of the first descriptor for this packet */
+ first = &tx_ring->tx_buf[tx_ring->next_to_use];
+
count = ice_xmit_desc_count(skb);
if (ice_chk_linearize(skb, count)) {
if (__skb_linearize(skb))
@@ -2183,8 +2195,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)
offload.tx_ring = tx_ring;
- /* record the location of the first descriptor for this packet */
- first = &tx_ring->tx_buf[tx_ring->next_to_use];
first->skb = skb;
first->type = ICE_TX_BUF_SKB;
first->bytecount = max_t(unsigned int, skb->len, ETH_ZLEN);
@@ -2249,6 +2259,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)
out_drop:
ice_trace(xmit_frame_ring_drop, tx_ring, skb);
dev_kfree_skb_any(skb);
+ first->type = ICE_TX_BUF_EMPTY;
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h
index b6547e1b7c42..5e517f219379 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.h
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.h
@@ -212,6 +212,14 @@ enum ice_rx_dtype {
ICE_RX_DTYPE_SPLIT_ALWAYS = 2,
};
+enum ice_tx_ring_flags {
+ ICE_TX_RING_FLAGS_XDP,
+ ICE_TX_RING_FLAGS_VLAN_L2TAG1,
+ ICE_TX_RING_FLAGS_VLAN_L2TAG2,
+ ICE_TX_RING_FLAGS_TXTIME,
+ ICE_TX_RING_FLAGS_NBITS,
+};
+
struct ice_pkt_ctx {
u64 cached_phctime;
__be16 vlan_proto;
@@ -352,11 +360,7 @@ struct ice_tx_ring {
u16 count; /* Number of descriptors */
u16 q_index; /* Queue number of ring */
- u8 flags;
-#define ICE_TX_FLAGS_RING_XDP BIT(0)
-#define ICE_TX_FLAGS_RING_VLAN_L2TAG1 BIT(1)
-#define ICE_TX_FLAGS_RING_VLAN_L2TAG2 BIT(2)
-#define ICE_TX_FLAGS_TXTIME BIT(3)
+ DECLARE_BITMAP(flags, ICE_TX_RING_FLAGS_NBITS);
struct xsk_buff_pool *xsk_pool;
@@ -398,7 +402,7 @@ static inline bool ice_ring_ch_enabled(struct ice_tx_ring *ring)
static inline bool ice_ring_is_xdp(struct ice_tx_ring *ring)
{
- return !!(ring->flags & ICE_TX_FLAGS_RING_XDP);
+ return test_bit(ICE_TX_RING_FLAGS_XDP, ring->flags);
}
enum ice_container_type {
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
index c8bc952f05cd..51259a4fdda4 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
@@ -804,7 +804,12 @@ void ice_reset_all_vfs(struct ice_pf *pf)
ice_vf_ctrl_invalidate_vsi(vf);
ice_vf_pre_vsi_rebuild(vf);
- ice_vf_rebuild_vsi(vf);
+ if (ice_vf_rebuild_vsi(vf)) {
+ dev_err(dev, "VF %u VSI rebuild failed, leaving VF disabled\n",
+ vf->vf_id);
+ mutex_unlock(&vf->cfg_lock);
+ continue;
+ }
ice_vf_post_vsi_rebuild(vf);
ice_eswitch_attach_vf(pf, vf);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_idc.c b/drivers/net/ethernet/intel/idpf/idpf_idc.c
index 7e4f4ac92653..b7d6b08fc89e 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_idc.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_idc.c
@@ -90,7 +90,10 @@ static int idpf_plug_vport_aux_dev(struct iidc_rdma_core_dev_info *cdev_info,
return 0;
err_aux_dev_add:
+ ida_free(&idpf_idc_ida, adev->id);
+ vdev_info->adev = NULL;
auxiliary_device_uninit(adev);
+ return ret;
err_aux_dev_init:
ida_free(&idpf_idc_ida, adev->id);
err_ida_alloc:
@@ -228,7 +231,10 @@ static int idpf_plug_core_aux_dev(struct iidc_rdma_core_dev_info *cdev_info)
return 0;
err_aux_dev_add:
+ ida_free(&idpf_idc_ida, adev->id);
+ cdev_info->adev = NULL;
auxiliary_device_uninit(adev);
+ return ret;
err_aux_dev_init:
ida_free(&idpf_idc_ida, adev->id);
err_ida_alloc:
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index ddc321a02fda..796f79088f36 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -3566,12 +3566,23 @@ static int mtk_device_event(struct notifier_block *n, unsigned long event, void
return NOTIFY_DONE;
}
+static int mtk_max_gmac_mtu(struct mtk_eth *eth)
+{
+ int i, max_mtu = ETH_DATA_LEN;
+
+ for (i = 0; i < ARRAY_SIZE(eth->netdev); i++)
+ if (eth->netdev[i] && eth->netdev[i]->mtu > max_mtu)
+ max_mtu = eth->netdev[i]->mtu;
+
+ return max_mtu;
+}
+
static int mtk_open(struct net_device *dev)
{
struct mtk_mac *mac = netdev_priv(dev);
struct mtk_eth *eth = mac->hw;
struct mtk_mac *target_mac;
- int i, err, ppe_num;
+ int i, err, ppe_num, mtu;
ppe_num = eth->soc->ppe_num;
@@ -3618,6 +3629,10 @@ static int mtk_open(struct net_device *dev)
mtk_gdm_config(eth, target_mac->id, gdm_config);
}
+ mtu = mtk_max_gmac_mtu(eth);
+ for (i = 0; i < ARRAY_SIZE(eth->ppe); i++)
+ mtk_ppe_update_mtu(eth->ppe[i], mtu);
+
napi_enable(ð->tx_napi);
napi_enable(ð->rx_napi);
mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
@@ -4311,6 +4326,7 @@ static int mtk_change_mtu(struct net_device *dev, int new_mtu)
int length = new_mtu + MTK_RX_ETH_HLEN;
struct mtk_mac *mac = netdev_priv(dev);
struct mtk_eth *eth = mac->hw;
+ int max_mtu, i;
if (rcu_access_pointer(eth->prog) &&
length > MTK_PP_MAX_BUF_SIZE) {
@@ -4321,6 +4337,10 @@ static int mtk_change_mtu(struct net_device *dev, int new_mtu)
mtk_set_mcr_max_rx(mac, length);
WRITE_ONCE(dev->mtu, new_mtu);
+ max_mtu = mtk_max_gmac_mtu(eth);
+ for (i = 0; i < ARRAY_SIZE(eth->ppe); i++)
+ mtk_ppe_update_mtu(eth->ppe[i], max_mtu);
+
return 0;
}
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
index 75f7728fc796..18279e2a7022 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
@@ -973,6 +973,36 @@ static void mtk_ppe_init_foe_table(struct mtk_ppe *ppe)
}
}
+void mtk_ppe_update_mtu(struct mtk_ppe *ppe, int mtu)
+{
+ int base;
+ u32 val;
+
+ if (!ppe)
+ return;
+
+ /* The PPE checks output frame size against per-tag-layer MTU limits,
+ * treating PPPoE and DSA tags just like 802.1Q VLAN tags. The Linux
+ * device MTU already accounts for PPPoE (PPPOE_SES_HLEN) and DSA tag
+ * overhead, but 802.1Q VLAN tags are handled transparently without
+ * being reflected by the lower device MTU being increased by 4.
+ * Use the maximum MTU across all GMAC interfaces so that PPE output
+ * frame limits are sufficiently high regardless of which port a flow
+ * egresses through.
+ */
+ base = ETH_HLEN + mtu;
+
+ val = FIELD_PREP(MTK_PPE_VLAN_MTU0_NONE, base) |
+ FIELD_PREP(MTK_PPE_VLAN_MTU0_1TAG, base + VLAN_HLEN);
+ ppe_w32(ppe, MTK_PPE_VLAN_MTU0, val);
+
+ val = FIELD_PREP(MTK_PPE_VLAN_MTU1_2TAG,
+ base + 2 * VLAN_HLEN) |
+ FIELD_PREP(MTK_PPE_VLAN_MTU1_3TAG,
+ base + 3 * VLAN_HLEN);
+ ppe_w32(ppe, MTK_PPE_VLAN_MTU1, val);
+}
+
void mtk_ppe_start(struct mtk_ppe *ppe)
{
u32 val;
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
index 223f709e2704..ba85e39a155b 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
@@ -346,6 +346,7 @@ struct mtk_ppe {
struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index);
void mtk_ppe_deinit(struct mtk_eth *eth);
+void mtk_ppe_update_mtu(struct mtk_ppe *ppe, int mtu);
void mtk_ppe_start(struct mtk_ppe *ppe);
int mtk_ppe_stop(struct mtk_ppe *ppe);
int mtk_ppe_prepare_reset(struct mtk_ppe *ppe);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c
index 05faad5083d9..145677ce9640 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2017, Mellanox Technologies inc. All rights reserved. */
+#include <linux/iopoll.h>
+
#include "mlx5_core.h"
#include "en.h"
#include "ipsec.h"
@@ -592,7 +594,6 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry,
struct mlx5_wqe_aso_ctrl_seg *ctrl;
struct mlx5e_hw_objs *res;
struct mlx5_aso_wqe *wqe;
- unsigned long expires;
u8 ds_cnt;
int ret;
@@ -614,13 +615,8 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry,
mlx5e_ipsec_aso_copy(ctrl, data);
mlx5_aso_post_wqe(aso->aso, false, &wqe->ctrl);
- expires = jiffies + msecs_to_jiffies(10);
- do {
- ret = mlx5_aso_poll_cq(aso->aso, false);
- if (ret)
- /* We are in atomic context */
- udelay(10);
- } while (ret && time_is_after_jiffies(expires));
+ read_poll_timeout_atomic(mlx5_aso_poll_cq, ret, !ret, 10,
+ 10 * USEC_PER_MSEC, false, aso->aso, false);
if (!ret)
memcpy(sa_entry->ctx, aso->ctx, MLX5_ST_SZ_BYTES(ipsec_aso));
spin_unlock_bh(&aso->lock);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index b6c12460b54a..0b8b44bbcb9e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -6756,6 +6756,14 @@ static int _mlx5e_probe(struct auxiliary_device *adev)
goto err_resume;
}
+ /* mlx5e_fix_features() returns early when the device is not present
+ * to avoid dereferencing cleared priv during profile changes.
+ * This also causes it to be a no-op during register_netdev(), where
+ * the device is not yet present.
+ * Trigger an additional features update that will actually work.
+ */
+ mlx5e_update_features(netdev);
+
mlx5e_dcbnl_init_app(priv);
mlx5_core_uplink_netdev_set(mdev, netdev);
mlx5e_params_print_info(mdev, &priv->channels.params);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 3f73d9b1115d..fab80c79ff07 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -1907,7 +1907,7 @@ int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx)
err = mlx5_notifiers_init(dev);
if (err)
- goto err_hca_caps;
+ goto err_notifiers_init;
/* The conjunction of sw_vhca_id with sw_owner_id will be a global
* unique id per function which uses mlx5_core.
@@ -1923,6 +1923,8 @@ int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx)
return 0;
+err_notifiers_init:
+ mlx5_hca_caps_free(dev);
err_hca_caps:
mlx5_adev_cleanup(dev);
err_adev_init:
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c
index 3fa9d1910daa..8f331358c972 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c
@@ -139,7 +139,7 @@ void fbnic_up(struct fbnic_net *fbn)
/* Enable Tx/Rx processing */
fbnic_napi_enable(fbn);
- netif_tx_start_all_queues(fbn->netdev);
+ netif_tx_wake_all_queues(fbn->netdev);
fbnic_service_task_start(fbn);
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index 786186c9a115..c2e855ff3ca9 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -2007,11 +2007,8 @@ static int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
gc->dev = &pdev->dev;
xa_init(&gc->irq_contexts);
- if (gc->is_pf)
- gc->mana_pci_debugfs = debugfs_create_dir("0", mana_debugfs_root);
- else
- gc->mana_pci_debugfs = debugfs_create_dir(pci_slot_name(pdev->slot),
- mana_debugfs_root);
+ gc->mana_pci_debugfs = debugfs_create_dir(pci_name(pdev),
+ mana_debugfs_root);
err = mana_gd_setup(pdev);
if (err)
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 6d87533924fa..14d6f68eaa69 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -3124,6 +3124,8 @@ static int mana_init_port(struct net_device *ndev)
eth_hw_addr_set(ndev, apc->mac_addr);
sprintf(vport, "vport%d", port_idx);
apc->mana_port_debugfs = debugfs_create_dir(vport, gc->mana_pci_debugfs);
+ debugfs_create_u32("current_speed", 0400, apc->mana_port_debugfs,
+ &apc->speed);
return 0;
reset_apc:
@@ -3402,8 +3404,6 @@ static int mana_probe_port(struct mana_context *ac, int port_idx,
netif_carrier_on(ndev);
- debugfs_create_u32("current_speed", 0400, apc->mana_port_debugfs, &apc->speed);
-
return 0;
free_indir:
@@ -3594,8 +3594,12 @@ int mana_probe(struct gdma_dev *gd, bool resuming)
ac->gdma_dev = gd;
gd->driver_data = ac;
+
+ INIT_WORK(&ac->link_change_work, mana_link_state_handle);
}
+ INIT_DELAYED_WORK(&ac->gf_stats_work, mana_gf_stats_work_handler);
+
err = mana_create_eq(ac);
if (err) {
dev_err(dev, "Failed to create EQs: %d\n", err);
@@ -3611,8 +3615,6 @@ int mana_probe(struct gdma_dev *gd, bool resuming)
if (!resuming) {
ac->num_ports = num_ports;
-
- INIT_WORK(&ac->link_change_work, mana_link_state_handle);
} else {
if (ac->num_ports != num_ports) {
dev_err(dev, "The number of vPorts changed: %d->%d\n",
@@ -3641,10 +3643,9 @@ int mana_probe(struct gdma_dev *gd, bool resuming)
if (!resuming) {
for (i = 0; i < ac->num_ports; i++) {
err = mana_probe_port(ac, i, &ac->ports[i]);
- /* we log the port for which the probe failed and stop
- * probes for subsequent ports.
- * Note that we keep running ports, for which the probes
- * were successful, unless add_adev fails too
+ /* Log the port for which the probe failed, stop probing
+ * subsequent ports, and skip add_adev.
+ * mana_remove() will clean up already-probed ports.
*/
if (err) {
dev_err(dev, "Probe Failed for port %d\n", i);
@@ -3658,10 +3659,9 @@ int mana_probe(struct gdma_dev *gd, bool resuming)
enable_work(&apc->queue_reset_work);
err = mana_attach(ac->ports[i]);
rtnl_unlock();
- /* we log the port for which the attach failed and stop
- * attach for subsequent ports
- * Note that we keep running ports, for which the attach
- * were successful, unless add_adev fails too
+ /* Log the port for which the attach failed, stop
+ * attaching subsequent ports, and skip add_adev.
+ * mana_remove() will clean up already-attached ports.
*/
if (err) {
dev_err(dev, "Attach Failed for port %d\n", i);
@@ -3670,9 +3670,9 @@ int mana_probe(struct gdma_dev *gd, bool resuming)
}
}
- err = add_adev(gd, "eth");
+ if (!err)
+ err = add_adev(gd, "eth");
- INIT_DELAYED_WORK(&ac->gf_stats_work, mana_gf_stats_work_handler);
schedule_delayed_work(&ac->gf_stats_work, MANA_GF_STATS_PERIOD);
out:
@@ -3693,11 +3693,16 @@ void mana_remove(struct gdma_dev *gd, bool suspending)
struct gdma_context *gc = gd->gdma_context;
struct mana_context *ac = gd->driver_data;
struct mana_port_context *apc;
- struct device *dev = gc->dev;
+ struct device *dev;
struct net_device *ndev;
int err;
int i;
+ if (!gc || !ac)
+ return;
+
+ dev = gc->dev;
+
disable_work_sync(&ac->link_change_work);
cancel_delayed_work_sync(&ac->gf_stats_work);
@@ -3710,7 +3715,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending)
if (!ndev) {
if (i == 0)
dev_err(dev, "No net device to remove\n");
- goto out;
+ break;
}
apc = netdev_priv(ndev);
@@ -3741,7 +3746,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending)
}
mana_destroy_eq(ac);
-out:
+
if (ac->per_port_queue_reset_wq) {
destroy_workqueue(ac->per_port_queue_reset_wq);
ac->per_port_queue_reset_wq = NULL;
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c
index 79470f198a62..9cf19446657c 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c
@@ -435,12 +435,17 @@ static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt,
/* Full Island ID and channel bits overlap? */
ret = nfp_decode_basic(addr, &v, cpp_tgt, mode, addr40, isld1, isld0);
- if (ret)
+ if (ret) {
+ pr_warn("%s: decode dest_island failed: %d\n", __func__, ret);
return ret;
+ }
/* The current address won't go where expected? */
- if (dest_island != -1 && dest_island != v)
+ if (dest_island != -1 && dest_island != v) {
+ pr_warn("%s: dest_island mismatch: current (%d) != decoded (%d)\n",
+ __func__, dest_island, v);
return -EINVAL;
+ }
/* If dest_island was -1, we don't care where it goes. */
return 0;
@@ -493,7 +498,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt,
* the address but we can verify if the existing
* contents will point to a valid island.
*/
- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island,
+ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt,
mode, addr40, isld1, isld0);
iid_lsb = addr40 ? 34 : 26;
@@ -504,7 +509,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt,
return 0;
case 1:
if (cpp_tgt == NFP_CPP_TARGET_QDR && !addr40)
- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island,
+ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt,
mode, addr40, isld1, isld0);
idx_lsb = addr40 ? 39 : 31;
@@ -530,7 +535,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt,
* be set before hand and with them select an island.
* So we need to confirm that it's at least plausible.
*/
- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island,
+ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt,
mode, addr40, isld1, isld0);
/* Make sure we compare against isldN values
@@ -551,7 +556,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt,
* iid<1> = addr<30> = channel<0>
* channel<1> = addr<31> = Index
*/
- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island,
+ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt,
mode, addr40, isld1, isld0);
isld[0] &= ~3;
diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
index d842c60dfc10..e5c6f81af48b 100644
--- a/drivers/net/ethernet/sfc/efx_devlink.c
+++ b/drivers/net/ethernet/sfc/efx_devlink.c
@@ -531,7 +531,7 @@ static int efx_devlink_info_running_versions(struct efx_nic *efx,
if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN) {
netif_err(efx, drv, efx->net_dev,
"mcdi MC_CMD_GET_VERSION failed\n");
- return rc;
+ return rc ?: -EIO;
}
/* Handle previous output */
diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
index 6da50f4b7c2e..f4276c9a7762 100644
--- a/drivers/net/ethernet/ti/Makefile
+++ b/drivers/net/ethernet/ti/Makefile
@@ -6,30 +6,30 @@
obj-$(CONFIG_TI_PRUETH) += icssm-prueth.o
icssm-prueth-y := icssm/icssm_prueth.o icssm/icssm_prueth_switch.o icssm/icssm_switchdev.o
-obj-$(CONFIG_TI_CPSW) += cpsw-common.o
-obj-$(CONFIG_TI_DAVINCI_EMAC) += cpsw-common.o
-obj-$(CONFIG_TI_CPSW_SWITCHDEV) += cpsw-common.o
+ti-cpsw-common-y += cpsw-common.o davinci_cpdma.o
+ti-cpsw-priv-y += cpsw_priv.o cpsw_ethtool.o
+ti-cpsw-ale-y += cpsw_ale.o
+ti-cpsw-sl-y += cpsw_sl.o
obj-$(CONFIG_TLAN) += tlan.o
-obj-$(CONFIG_TI_DAVINCI_EMAC) += ti_davinci_emac.o
-ti_davinci_emac-y := davinci_emac.o davinci_cpdma.o
+obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci_emac.o ti-cpsw-common.o
obj-$(CONFIG_TI_DAVINCI_MDIO) += davinci_mdio.o
obj-$(CONFIG_TI_CPSW_PHY_SEL) += cpsw-phy-sel.o
obj-$(CONFIG_TI_CPTS) += cpts.o
-obj-$(CONFIG_TI_CPSW) += ti_cpsw.o
-ti_cpsw-y := cpsw.o davinci_cpdma.o cpsw_ale.o cpsw_priv.o cpsw_sl.o cpsw_ethtool.o
-obj-$(CONFIG_TI_CPSW_SWITCHDEV) += ti_cpsw_new.o
-ti_cpsw_new-y := cpsw_switchdev.o cpsw_new.o davinci_cpdma.o cpsw_ale.o cpsw_sl.o cpsw_priv.o cpsw_ethtool.o
+obj-$(CONFIG_TI_CPSW) += ti_cpsw.o ti-cpsw-common.o ti-cpsw-priv.o ti-cpsw-ale.o ti-cpsw-sl.o
+ti_cpsw-y := cpsw.o
+obj-$(CONFIG_TI_CPSW_SWITCHDEV) += ti_cpsw_new.o ti-cpsw-common.o ti-cpsw-priv.o ti-cpsw-ale.o ti-cpsw-sl.o
+ti_cpsw_new-y := cpsw_switchdev.o cpsw_new.o
-obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o
-keystone_netcp-y := netcp_core.o cpsw_ale.o
-obj-$(CONFIG_TI_KEYSTONE_NETCP_ETHSS) += keystone_netcp_ethss.o
-keystone_netcp_ethss-y := netcp_ethss.o netcp_sgmii.o netcp_xgbepcsr.o cpsw_ale.o
+obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o ti-cpsw-ale.o
+keystone_netcp-y := netcp_core.o
+obj-$(CONFIG_TI_KEYSTONE_NETCP_ETHSS) += keystone_netcp_ethss.o ti-cpsw-ale.o
+keystone_netcp_ethss-y := netcp_ethss.o netcp_sgmii.o netcp_xgbepcsr.o
obj-$(CONFIG_TI_K3_CPPI_DESC_POOL) += k3-cppi-desc-pool.o
-obj-$(CONFIG_TI_K3_AM65_CPSW_NUSS) += ti-am65-cpsw-nuss.o
-ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o cpsw_sl.o am65-cpsw-ethtool.o cpsw_ale.o
+obj-$(CONFIG_TI_K3_AM65_CPSW_NUSS) += ti-am65-cpsw-nuss.o ti-cpsw-sl.o ti-cpsw-ale.o
+ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o am65-cpsw-ethtool.o
ti-am65-cpsw-nuss-$(CONFIG_TI_AM65_CPSW_QOS) += am65-cpsw-qos.o
ti-am65-cpsw-nuss-$(CONFIG_TI_K3_AM65_CPSW_SWITCHDEV) += am65-cpsw-switchdev.o
obj-$(CONFIG_TI_K3_AM65_CPTS) += am65-cpts.o
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index b0e18bdc2c85..aa3531e844e8 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -706,7 +706,7 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
struct cpsw_common *cpsw = priv->cpsw;
/* soft reset the controller and initialize ale */
- soft_reset("cpsw", &cpsw->regs->soft_reset);
+ cpsw_soft_reset("cpsw", &cpsw->regs->soft_reset);
cpsw_ale_start(cpsw->ale);
/* switch to vlan aware mode */
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
index be7b69319221..e202bba49480 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.c
+++ b/drivers/net/ethernet/ti/cpsw_ale.c
@@ -493,6 +493,7 @@ int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid)
}
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_flush_multicast);
static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry,
int flags, u16 vid)
@@ -530,6 +531,7 @@ int cpsw_ale_add_ucast(struct cpsw_ale *ale, const u8 *addr, int port,
cpsw_ale_write(ale, idx, ale_entry);
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_add_ucast);
int cpsw_ale_del_ucast(struct cpsw_ale *ale, const u8 *addr, int port,
int flags, u16 vid)
@@ -545,6 +547,7 @@ int cpsw_ale_del_ucast(struct cpsw_ale *ale, const u8 *addr, int port,
cpsw_ale_write(ale, idx, ale_entry);
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_del_ucast);
int cpsw_ale_add_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask,
int flags, u16 vid, int mcast_state)
@@ -578,6 +581,7 @@ int cpsw_ale_add_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask,
cpsw_ale_write(ale, idx, ale_entry);
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_add_mcast);
int cpsw_ale_del_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask,
int flags, u16 vid)
@@ -607,6 +611,7 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask,
cpsw_ale_write(ale, idx, ale_entry);
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_del_mcast);
/* ALE NetCP NU switch specific vlan functions */
static void cpsw_ale_set_vlan_mcast(struct cpsw_ale *ale, u32 *ale_entry,
@@ -676,6 +681,7 @@ int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port_mask, int untag,
cpsw_ale_write(ale, idx, ale_entry);
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_add_vlan);
static void cpsw_ale_vlan_del_modify_int(struct cpsw_ale *ale, u32 *ale_entry,
u16 vid, int port_mask)
@@ -733,6 +739,7 @@ int cpsw_ale_vlan_del_modify(struct cpsw_ale *ale, u16 vid, int port_mask)
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_vlan_del_modify);
int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
{
@@ -767,6 +774,7 @@ int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_del_vlan);
int cpsw_ale_vlan_add_modify(struct cpsw_ale *ale, u16 vid, int port_mask,
int untag_mask, int reg_mask, int unreg_mask)
@@ -806,6 +814,7 @@ int cpsw_ale_vlan_add_modify(struct cpsw_ale *ale, u16 vid, int port_mask,
return ret;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_vlan_add_modify);
void cpsw_ale_set_unreg_mcast(struct cpsw_ale *ale, int unreg_mcast_mask,
bool add)
@@ -833,6 +842,7 @@ void cpsw_ale_set_unreg_mcast(struct cpsw_ale *ale, int unreg_mcast_mask,
cpsw_ale_write(ale, idx, ale_entry);
}
}
+EXPORT_SYMBOL_GPL(cpsw_ale_set_unreg_mcast);
static void cpsw_ale_vlan_set_unreg_mcast(struct cpsw_ale *ale, u32 *ale_entry,
int allmulti)
@@ -898,6 +908,7 @@ void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti, int port)
cpsw_ale_write(ale, idx, ale_entry);
}
}
+EXPORT_SYMBOL_GPL(cpsw_ale_set_allmulti);
struct ale_control_info {
const char *name;
@@ -1155,6 +1166,7 @@ int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int control,
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_control_set);
int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control)
{
@@ -1178,6 +1190,7 @@ int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control)
tmp = readl_relaxed(ale->params.ale_regs + offset) >> shift;
return tmp & BITMASK(info->bits);
}
+EXPORT_SYMBOL_GPL(cpsw_ale_control_get);
int cpsw_ale_rx_ratelimit_mc(struct cpsw_ale *ale, int port, unsigned int ratelimit_pps)
@@ -1200,6 +1213,7 @@ int cpsw_ale_rx_ratelimit_mc(struct cpsw_ale *ale, int port, unsigned int rateli
port, val * ALE_RATE_LIMIT_MIN_PPS);
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_rx_ratelimit_mc);
int cpsw_ale_rx_ratelimit_bc(struct cpsw_ale *ale, int port, unsigned int ratelimit_pps)
@@ -1222,6 +1236,7 @@ int cpsw_ale_rx_ratelimit_bc(struct cpsw_ale *ale, int port, unsigned int rateli
port, val * ALE_RATE_LIMIT_MIN_PPS);
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_rx_ratelimit_bc);
static void cpsw_ale_timer(struct timer_list *t)
{
@@ -1311,6 +1326,7 @@ void cpsw_ale_start(struct cpsw_ale *ale)
cpsw_ale_aging_start(ale);
}
+EXPORT_SYMBOL_GPL(cpsw_ale_start);
void cpsw_ale_stop(struct cpsw_ale *ale)
{
@@ -1318,6 +1334,7 @@ void cpsw_ale_stop(struct cpsw_ale *ale)
cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1);
cpsw_ale_control_set(ale, 0, ALE_ENABLE, 0);
}
+EXPORT_SYMBOL_GPL(cpsw_ale_stop);
static const struct reg_field ale_fields_cpsw[] = {
/* CPSW_ALE_IDVER_REG */
@@ -1618,6 +1635,7 @@ struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params)
cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1);
return ale;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_create);
void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data)
{
@@ -1628,6 +1646,7 @@ void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data)
data += ALE_ENTRY_WORDS;
}
}
+EXPORT_SYMBOL_GPL(cpsw_ale_dump);
void cpsw_ale_restore(struct cpsw_ale *ale, u32 *data)
{
@@ -1638,11 +1657,13 @@ void cpsw_ale_restore(struct cpsw_ale *ale, u32 *data)
data += ALE_ENTRY_WORDS;
}
}
+EXPORT_SYMBOL_GPL(cpsw_ale_restore);
u32 cpsw_ale_get_num_entries(struct cpsw_ale *ale)
{
return ale ? ale->params.ale_entries : 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_get_num_entries);
/* Reads the specified policer index into ALE POLICER registers */
static void cpsw_ale_policer_read_idx(struct cpsw_ale *ale, u32 idx)
@@ -1745,3 +1766,7 @@ void cpsw_ale_classifier_setup_default(struct cpsw_ale *ale, int num_rx_ch)
1);
}
}
+EXPORT_SYMBOL_GPL(cpsw_ale_classifier_setup_default);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("TI N-Port Ethernet Switch Address Lookup Engine");
diff --git a/drivers/net/ethernet/ti/cpsw_ethtool.c b/drivers/net/ethernet/ti/cpsw_ethtool.c
index a43f75ee269e..3f2682c461f9 100644
--- a/drivers/net/ethernet/ti/cpsw_ethtool.c
+++ b/drivers/net/ethernet/ti/cpsw_ethtool.c
@@ -144,6 +144,7 @@ u32 cpsw_get_msglevel(struct net_device *ndev)
return priv->msg_enable;
}
+EXPORT_SYMBOL_GPL(cpsw_get_msglevel);
void cpsw_set_msglevel(struct net_device *ndev, u32 value)
{
@@ -151,6 +152,7 @@ void cpsw_set_msglevel(struct net_device *ndev, u32 value)
priv->msg_enable = value;
}
+EXPORT_SYMBOL_GPL(cpsw_set_msglevel);
int cpsw_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal,
struct kernel_ethtool_coalesce *kernel_coal,
@@ -161,6 +163,7 @@ int cpsw_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal,
coal->rx_coalesce_usecs = cpsw->coal_intvl;
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_get_coalesce);
int cpsw_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal,
struct kernel_ethtool_coalesce *kernel_coal,
@@ -220,6 +223,7 @@ int cpsw_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal,
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_set_coalesce);
int cpsw_get_sset_count(struct net_device *ndev, int sset)
{
@@ -234,6 +238,7 @@ int cpsw_get_sset_count(struct net_device *ndev, int sset)
return -EOPNOTSUPP;
}
}
+EXPORT_SYMBOL_GPL(cpsw_get_sset_count);
static void cpsw_add_ch_strings(u8 **p, int ch_num, int rx_dir)
{
@@ -271,6 +276,7 @@ void cpsw_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
break;
}
}
+EXPORT_SYMBOL_GPL(cpsw_get_strings);
void cpsw_get_ethtool_stats(struct net_device *ndev,
struct ethtool_stats *stats, u64 *data)
@@ -303,6 +309,7 @@ void cpsw_get_ethtool_stats(struct net_device *ndev,
}
}
}
+EXPORT_SYMBOL_GPL(cpsw_get_ethtool_stats);
void cpsw_get_pauseparam(struct net_device *ndev,
struct ethtool_pauseparam *pause)
@@ -313,6 +320,7 @@ void cpsw_get_pauseparam(struct net_device *ndev,
pause->rx_pause = priv->rx_pause ? true : false;
pause->tx_pause = priv->tx_pause ? true : false;
}
+EXPORT_SYMBOL_GPL(cpsw_get_pauseparam);
void cpsw_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
{
@@ -326,6 +334,7 @@ void cpsw_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
if (cpsw->slaves[slave_no].phy)
phy_ethtool_get_wol(cpsw->slaves[slave_no].phy, wol);
}
+EXPORT_SYMBOL_GPL(cpsw_get_wol);
int cpsw_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
{
@@ -338,6 +347,7 @@ int cpsw_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
else
return -EOPNOTSUPP;
}
+EXPORT_SYMBOL_GPL(cpsw_set_wol);
int cpsw_get_regs_len(struct net_device *ndev)
{
@@ -346,6 +356,7 @@ int cpsw_get_regs_len(struct net_device *ndev)
return cpsw_ale_get_num_entries(cpsw->ale) *
ALE_ENTRY_WORDS * sizeof(u32);
}
+EXPORT_SYMBOL_GPL(cpsw_get_regs_len);
void cpsw_get_regs(struct net_device *ndev, struct ethtool_regs *regs, void *p)
{
@@ -357,6 +368,7 @@ void cpsw_get_regs(struct net_device *ndev, struct ethtool_regs *regs, void *p)
cpsw_ale_dump(cpsw->ale, reg);
}
+EXPORT_SYMBOL_GPL(cpsw_get_regs);
int cpsw_ethtool_op_begin(struct net_device *ndev)
{
@@ -370,6 +382,7 @@ int cpsw_ethtool_op_begin(struct net_device *ndev)
return ret;
}
+EXPORT_SYMBOL_GPL(cpsw_ethtool_op_begin);
void cpsw_ethtool_op_complete(struct net_device *ndev)
{
@@ -377,6 +390,7 @@ void cpsw_ethtool_op_complete(struct net_device *ndev)
pm_runtime_put(priv->cpsw->dev);
}
+EXPORT_SYMBOL_GPL(cpsw_ethtool_op_complete);
void cpsw_get_channels(struct net_device *ndev, struct ethtool_channels *ch)
{
@@ -391,6 +405,7 @@ void cpsw_get_channels(struct net_device *ndev, struct ethtool_channels *ch)
ch->tx_count = cpsw->tx_ch_num;
ch->combined_count = 0;
}
+EXPORT_SYMBOL_GPL(cpsw_get_channels);
int cpsw_get_link_ksettings(struct net_device *ndev,
struct ethtool_link_ksettings *ecmd)
@@ -405,6 +420,7 @@ int cpsw_get_link_ksettings(struct net_device *ndev,
phy_ethtool_ksettings_get(cpsw->slaves[slave_no].phy, ecmd);
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_get_link_ksettings);
int cpsw_set_link_ksettings(struct net_device *ndev,
const struct ethtool_link_ksettings *ecmd)
@@ -418,6 +434,7 @@ int cpsw_set_link_ksettings(struct net_device *ndev,
return phy_ethtool_ksettings_set(cpsw->slaves[slave_no].phy, ecmd);
}
+EXPORT_SYMBOL_GPL(cpsw_set_link_ksettings);
int cpsw_get_eee(struct net_device *ndev, struct ethtool_keee *edata)
{
@@ -430,6 +447,7 @@ int cpsw_get_eee(struct net_device *ndev, struct ethtool_keee *edata)
else
return -EOPNOTSUPP;
}
+EXPORT_SYMBOL_GPL(cpsw_get_eee);
int cpsw_nway_reset(struct net_device *ndev)
{
@@ -442,6 +460,7 @@ int cpsw_nway_reset(struct net_device *ndev)
else
return -EOPNOTSUPP;
}
+EXPORT_SYMBOL_GPL(cpsw_nway_reset);
static void cpsw_suspend_data_pass(struct net_device *ndev)
{
@@ -639,6 +658,7 @@ int cpsw_set_channels_common(struct net_device *ndev,
cpsw_fail(cpsw);
return ret;
}
+EXPORT_SYMBOL_GPL(cpsw_set_channels_common);
void cpsw_get_ringparam(struct net_device *ndev,
struct ethtool_ringparam *ering,
@@ -654,6 +674,7 @@ void cpsw_get_ringparam(struct net_device *ndev,
ering->rx_max_pending = cpsw->descs_pool_size - CPSW_MAX_QUEUES;
ering->rx_pending = cpdma_get_num_rx_descs(cpsw->dma);
}
+EXPORT_SYMBOL_GPL(cpsw_get_ringparam);
int cpsw_set_ringparam(struct net_device *ndev,
struct ethtool_ringparam *ering,
@@ -700,6 +721,7 @@ int cpsw_set_ringparam(struct net_device *ndev,
cpsw_fail(cpsw);
return ret;
}
+EXPORT_SYMBOL_GPL(cpsw_set_ringparam);
#if IS_ENABLED(CONFIG_TI_CPTS)
int cpsw_get_ts_info(struct net_device *ndev, struct kernel_ethtool_ts_info *info)
@@ -720,6 +742,7 @@ int cpsw_get_ts_info(struct net_device *ndev, struct kernel_ethtool_ts_info *inf
(1 << HWTSTAMP_FILTER_PTP_V2_EVENT);
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_get_ts_info);
#else
int cpsw_get_ts_info(struct net_device *ndev, struct kernel_ethtool_ts_info *info)
{
@@ -729,4 +752,5 @@ int cpsw_get_ts_info(struct net_device *ndev, struct kernel_ethtool_ts_info *inf
info->rx_filters = 0;
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_get_ts_info);
#endif
diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c
index 7f42f58a4b03..c5be359f3c66 100644
--- a/drivers/net/ethernet/ti/cpsw_new.c
+++ b/drivers/net/ethernet/ti/cpsw_new.c
@@ -573,7 +573,7 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
u32 control_reg;
/* soft reset the controller and initialize ale */
- soft_reset("cpsw", &cpsw->regs->soft_reset);
+ cpsw_soft_reset("cpsw", &cpsw->regs->soft_reset);
cpsw_ale_start(cpsw->ale);
/* switch to vlan aware mode */
diff --git a/drivers/net/ethernet/ti/cpsw_priv.c b/drivers/net/ethernet/ti/cpsw_priv.c
index bc4fdf17a99e..1f6f374551cb 100644
--- a/drivers/net/ethernet/ti/cpsw_priv.c
+++ b/drivers/net/ethernet/ti/cpsw_priv.c
@@ -32,6 +32,7 @@
#define CPTS_N_ETX_TS 4
int (*cpsw_slave_index)(struct cpsw_common *cpsw, struct cpsw_priv *priv);
+EXPORT_SYMBOL_GPL(cpsw_slave_index);
void cpsw_intr_enable(struct cpsw_common *cpsw)
{
@@ -40,6 +41,7 @@ void cpsw_intr_enable(struct cpsw_common *cpsw)
cpdma_ctlr_int_ctrl(cpsw->dma, true);
}
+EXPORT_SYMBOL_GPL(cpsw_intr_enable);
void cpsw_intr_disable(struct cpsw_common *cpsw)
{
@@ -48,6 +50,7 @@ void cpsw_intr_disable(struct cpsw_common *cpsw)
cpdma_ctlr_int_ctrl(cpsw->dma, false);
}
+EXPORT_SYMBOL_GPL(cpsw_intr_disable);
void cpsw_tx_handler(void *token, int len, int status)
{
@@ -82,6 +85,7 @@ void cpsw_tx_handler(void *token, int len, int status)
ndev->stats.tx_packets++;
ndev->stats.tx_bytes += len;
}
+EXPORT_SYMBOL_GPL(cpsw_tx_handler);
irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id)
{
@@ -98,6 +102,7 @@ irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id)
napi_schedule(&cpsw->napi_tx);
return IRQ_HANDLED;
}
+EXPORT_SYMBOL_GPL(cpsw_tx_interrupt);
irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id)
{
@@ -114,6 +119,7 @@ irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id)
napi_schedule(&cpsw->napi_rx);
return IRQ_HANDLED;
}
+EXPORT_SYMBOL_GPL(cpsw_rx_interrupt);
irqreturn_t cpsw_misc_interrupt(int irq, void *dev_id)
{
@@ -126,6 +132,7 @@ irqreturn_t cpsw_misc_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+EXPORT_SYMBOL_GPL(cpsw_misc_interrupt);
int cpsw_tx_mq_poll(struct napi_struct *napi_tx, int budget)
{
@@ -158,6 +165,7 @@ int cpsw_tx_mq_poll(struct napi_struct *napi_tx, int budget)
return num_tx;
}
+EXPORT_SYMBOL_GPL(cpsw_tx_mq_poll);
int cpsw_tx_poll(struct napi_struct *napi_tx, int budget)
{
@@ -176,6 +184,7 @@ int cpsw_tx_poll(struct napi_struct *napi_tx, int budget)
return num_tx;
}
+EXPORT_SYMBOL_GPL(cpsw_tx_poll);
int cpsw_rx_mq_poll(struct napi_struct *napi_rx, int budget)
{
@@ -208,6 +217,7 @@ int cpsw_rx_mq_poll(struct napi_struct *napi_rx, int budget)
return num_rx;
}
+EXPORT_SYMBOL_GPL(cpsw_rx_mq_poll);
int cpsw_rx_poll(struct napi_struct *napi_rx, int budget)
{
@@ -226,6 +236,7 @@ int cpsw_rx_poll(struct napi_struct *napi_rx, int budget)
return num_rx;
}
+EXPORT_SYMBOL_GPL(cpsw_rx_poll);
void cpsw_rx_vlan_encap(struct sk_buff *skb)
{
@@ -268,14 +279,16 @@ void cpsw_rx_vlan_encap(struct sk_buff *skb)
skb_pull(skb, VLAN_HLEN);
}
}
+EXPORT_SYMBOL_GPL(cpsw_rx_vlan_encap);
void cpsw_set_slave_mac(struct cpsw_slave *slave, struct cpsw_priv *priv)
{
slave_write(slave, mac_hi(priv->mac_addr), SA_HI);
slave_write(slave, mac_lo(priv->mac_addr), SA_LO);
}
+EXPORT_SYMBOL_GPL(cpsw_set_slave_mac);
-void soft_reset(const char *module, void __iomem *reg)
+void cpsw_soft_reset(const char *module, void __iomem *reg)
{
unsigned long timeout = jiffies + HZ;
@@ -286,6 +299,7 @@ void soft_reset(const char *module, void __iomem *reg)
WARN(readl_relaxed(reg) & 1, "failed to soft-reset %s\n", module);
}
+EXPORT_SYMBOL_GPL(cpsw_soft_reset);
void cpsw_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue)
{
@@ -305,6 +319,7 @@ void cpsw_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue)
netif_trans_update(ndev);
netif_tx_wake_all_queues(ndev);
}
+EXPORT_SYMBOL_GPL(cpsw_ndo_tx_timeout);
static int cpsw_get_common_speed(struct cpsw_common *cpsw)
{
@@ -343,6 +358,7 @@ int cpsw_need_resplit(struct cpsw_common *cpsw)
return 1;
}
+EXPORT_SYMBOL_GPL(cpsw_need_resplit);
void cpsw_split_res(struct cpsw_common *cpsw)
{
@@ -428,6 +444,7 @@ void cpsw_split_res(struct cpsw_common *cpsw)
if (budget)
cpsw->rxv[0].budget += budget;
}
+EXPORT_SYMBOL_GPL(cpsw_split_res);
int cpsw_init_common(struct cpsw_common *cpsw, void __iomem *ss_regs,
int ale_ageout, phys_addr_t desc_mem_phys,
@@ -548,6 +565,7 @@ int cpsw_init_common(struct cpsw_common *cpsw, void __iomem *ss_regs,
return ret;
}
+EXPORT_SYMBOL_GPL(cpsw_init_common);
#if IS_ENABLED(CONFIG_TI_CPTS)
@@ -678,6 +696,7 @@ int cpsw_hwtstamp_set(struct net_device *dev,
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_hwtstamp_set);
int cpsw_hwtstamp_get(struct net_device *dev,
struct kernel_hwtstamp_config *cfg)
@@ -695,12 +714,14 @@ int cpsw_hwtstamp_get(struct net_device *dev,
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_hwtstamp_get);
#else
int cpsw_hwtstamp_get(struct net_device *dev,
struct kernel_hwtstamp_config *cfg)
{
return -EOPNOTSUPP;
}
+EXPORT_SYMBOL_GPL(cpsw_hwtstamp_set);
int cpsw_hwtstamp_set(struct net_device *dev,
struct kernel_hwtstamp_config *cfg,
@@ -708,6 +729,7 @@ int cpsw_hwtstamp_set(struct net_device *dev,
{
return -EOPNOTSUPP;
}
+EXPORT_SYMBOL_GPL(cpsw_hwtstamp_get);
#endif /*CONFIG_TI_CPTS*/
int cpsw_ndo_set_tx_maxrate(struct net_device *ndev, int queue, u32 rate)
@@ -758,6 +780,7 @@ int cpsw_ndo_set_tx_maxrate(struct net_device *ndev, int queue, u32 rate)
cpsw_split_res(cpsw);
return ret;
}
+EXPORT_SYMBOL_GPL(cpsw_ndo_set_tx_maxrate);
static int cpsw_tc_to_fifo(int tc, int num_tc)
{
@@ -782,6 +805,7 @@ bool cpsw_shp_is_off(struct cpsw_priv *priv)
return !val;
}
+EXPORT_SYMBOL_GPL(cpsw_shp_is_off);
static void cpsw_fifo_shp_on(struct cpsw_priv *priv, int fifo, int on)
{
@@ -1043,6 +1067,7 @@ int cpsw_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type,
return -EOPNOTSUPP;
}
}
+EXPORT_SYMBOL_GPL(cpsw_ndo_setup_tc);
void cpsw_cbs_resume(struct cpsw_slave *slave, struct cpsw_priv *priv)
{
@@ -1056,6 +1081,7 @@ void cpsw_cbs_resume(struct cpsw_slave *slave, struct cpsw_priv *priv)
cpsw_set_fifo_rlimit(priv, fifo, bw);
}
}
+EXPORT_SYMBOL_GPL(cpsw_cbs_resume);
void cpsw_mqprio_resume(struct cpsw_slave *slave, struct cpsw_priv *priv)
{
@@ -1078,6 +1104,7 @@ void cpsw_mqprio_resume(struct cpsw_slave *slave, struct cpsw_priv *priv)
slave_write(slave, tx_prio_map, tx_prio_rg);
}
+EXPORT_SYMBOL_GPL(cpsw_mqprio_resume);
int cpsw_fill_rx_channels(struct cpsw_priv *priv)
{
@@ -1123,6 +1150,7 @@ int cpsw_fill_rx_channels(struct cpsw_priv *priv)
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_fill_rx_channels);
static struct page_pool *cpsw_create_page_pool(struct cpsw_common *cpsw,
int size)
@@ -1208,6 +1236,7 @@ void cpsw_destroy_xdp_rxqs(struct cpsw_common *cpsw)
cpsw->page_pool[ch] = NULL;
}
}
+EXPORT_SYMBOL_GPL(cpsw_destroy_xdp_rxqs);
int cpsw_create_xdp_rxqs(struct cpsw_common *cpsw)
{
@@ -1240,6 +1269,7 @@ int cpsw_create_xdp_rxqs(struct cpsw_common *cpsw)
return ret;
}
+EXPORT_SYMBOL_GPL(cpsw_create_xdp_rxqs);
static int cpsw_xdp_prog_setup(struct cpsw_priv *priv, struct netdev_bpf *bpf)
{
@@ -1267,6 +1297,7 @@ int cpsw_ndo_bpf(struct net_device *ndev, struct netdev_bpf *bpf)
return -EINVAL;
}
}
+EXPORT_SYMBOL_GPL(cpsw_ndo_bpf);
int cpsw_xdp_tx_frame(struct cpsw_priv *priv, struct xdp_frame *xdpf,
struct page *page, int port)
@@ -1300,6 +1331,7 @@ int cpsw_xdp_tx_frame(struct cpsw_priv *priv, struct xdp_frame *xdpf,
return ret;
}
+EXPORT_SYMBOL_GPL(cpsw_xdp_tx_frame);
int cpsw_run_xdp(struct cpsw_priv *priv, int ch, struct xdp_buff *xdp,
struct page *page, int port, int *len)
@@ -1362,6 +1394,7 @@ int cpsw_run_xdp(struct cpsw_priv *priv, int ch, struct xdp_buff *xdp,
page_pool_recycle_direct(cpsw->page_pool[ch], page);
return ret;
}
+EXPORT_SYMBOL_GPL(cpsw_run_xdp);
static int cpsw_qos_clsflower_add_policer(struct cpsw_priv *priv,
struct netlink_ext_ack *extack,
@@ -1564,3 +1597,7 @@ void cpsw_qos_clsflower_resume(struct cpsw_priv *priv)
cpsw_ale_rx_ratelimit_mc(priv->cpsw->ale, port_id,
priv->ale_mc_ratelimit.rate_packet_ps);
}
+EXPORT_SYMBOL_GPL(cpsw_qos_clsflower_resume);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("TI CPSW Ethernet Switch Driver");
diff --git a/drivers/net/ethernet/ti/cpsw_priv.h b/drivers/net/ethernet/ti/cpsw_priv.h
index acb6181c5c9e..fddd7a79f4b0 100644
--- a/drivers/net/ethernet/ti/cpsw_priv.h
+++ b/drivers/net/ethernet/ti/cpsw_priv.h
@@ -458,7 +458,7 @@ int cpsw_tx_poll(struct napi_struct *napi_tx, int budget);
int cpsw_rx_mq_poll(struct napi_struct *napi_rx, int budget);
int cpsw_rx_poll(struct napi_struct *napi_rx, int budget);
void cpsw_rx_vlan_encap(struct sk_buff *skb);
-void soft_reset(const char *module, void __iomem *reg);
+void cpsw_soft_reset(const char *module, void __iomem *reg);
void cpsw_set_slave_mac(struct cpsw_slave *slave, struct cpsw_priv *priv);
void cpsw_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue);
int cpsw_need_resplit(struct cpsw_common *cpsw);
diff --git a/drivers/net/ethernet/ti/cpsw_sl.c b/drivers/net/ethernet/ti/cpsw_sl.c
index 0c7531cb0f39..761719a348fa 100644
--- a/drivers/net/ethernet/ti/cpsw_sl.c
+++ b/drivers/net/ethernet/ti/cpsw_sl.c
@@ -200,6 +200,7 @@ u32 cpsw_sl_reg_read(struct cpsw_sl *sl, enum cpsw_sl_regs reg)
dev_dbg(sl->dev, "cpsw_sl: reg: %04X r 0x%08X\n", sl->regs[reg], val);
return val;
}
+EXPORT_SYMBOL_GPL(cpsw_sl_reg_read);
void cpsw_sl_reg_write(struct cpsw_sl *sl, enum cpsw_sl_regs reg, u32 val)
{
@@ -212,6 +213,7 @@ void cpsw_sl_reg_write(struct cpsw_sl *sl, enum cpsw_sl_regs reg, u32 val)
dev_dbg(sl->dev, "cpsw_sl: reg: %04X w 0x%08X\n", sl->regs[reg], val);
writel(val, sl->sl_base + sl->regs[reg]);
}
+EXPORT_SYMBOL_GPL(cpsw_sl_reg_write);
static const struct cpsw_sl_dev_id *cpsw_sl_match_id(
const struct cpsw_sl_dev_id *id,
@@ -252,6 +254,7 @@ struct cpsw_sl *cpsw_sl_get(const char *device_id, struct device *dev,
return sl;
}
+EXPORT_SYMBOL_GPL(cpsw_sl_get);
void cpsw_sl_reset(struct cpsw_sl *sl, unsigned long tmo)
{
@@ -270,6 +273,7 @@ void cpsw_sl_reset(struct cpsw_sl *sl, unsigned long tmo)
if (cpsw_sl_reg_read(sl, CPSW_SL_SOFT_RESET) & CPSW_SL_SOFT_RESET_BIT)
dev_err(sl->dev, "cpsw_sl failed to soft-reset.\n");
}
+EXPORT_SYMBOL_GPL(cpsw_sl_reset);
u32 cpsw_sl_ctl_set(struct cpsw_sl *sl, u32 ctl_funcs)
{
@@ -287,6 +291,7 @@ u32 cpsw_sl_ctl_set(struct cpsw_sl *sl, u32 ctl_funcs)
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_sl_ctl_set);
u32 cpsw_sl_ctl_clr(struct cpsw_sl *sl, u32 ctl_funcs)
{
@@ -304,11 +309,13 @@ u32 cpsw_sl_ctl_clr(struct cpsw_sl *sl, u32 ctl_funcs)
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_sl_ctl_clr);
void cpsw_sl_ctl_reset(struct cpsw_sl *sl)
{
cpsw_sl_reg_write(sl, CPSW_SL_MACCONTROL, 0);
}
+EXPORT_SYMBOL_GPL(cpsw_sl_ctl_reset);
int cpsw_sl_wait_for_idle(struct cpsw_sl *sl, unsigned long tmo)
{
@@ -326,3 +333,7 @@ int cpsw_sl_wait_for_idle(struct cpsw_sl *sl, unsigned long tmo)
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_sl_wait_for_idle);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("TI Ethernet Switch media-access-controller (MAC) submodule");
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c
index d2eab5cd1e0c..41e89a19be53 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.c
+++ b/drivers/net/ethernet/ti/davinci_cpdma.c
@@ -531,6 +531,7 @@ struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params)
ctlr->num_chan = CPDMA_MAX_CHANNELS;
return ctlr;
}
+EXPORT_SYMBOL_GPL(cpdma_ctlr_create);
int cpdma_ctlr_start(struct cpdma_ctlr *ctlr)
{
@@ -591,6 +592,7 @@ int cpdma_ctlr_start(struct cpdma_ctlr *ctlr)
spin_unlock_irqrestore(&ctlr->lock, flags);
return 0;
}
+EXPORT_SYMBOL_GPL(cpdma_ctlr_start);
int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr)
{
@@ -623,6 +625,7 @@ int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr)
spin_unlock_irqrestore(&ctlr->lock, flags);
return 0;
}
+EXPORT_SYMBOL_GPL(cpdma_ctlr_stop);
int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr)
{
@@ -640,6 +643,7 @@ int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr)
cpdma_desc_pool_destroy(ctlr);
return ret;
}
+EXPORT_SYMBOL_GPL(cpdma_ctlr_destroy);
int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable)
{
@@ -660,21 +664,25 @@ int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable)
spin_unlock_irqrestore(&ctlr->lock, flags);
return 0;
}
+EXPORT_SYMBOL_GPL(cpdma_ctlr_int_ctrl);
void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr, u32 value)
{
dma_reg_write(ctlr, CPDMA_MACEOIVECTOR, value);
}
+EXPORT_SYMBOL_GPL(cpdma_ctlr_eoi);
u32 cpdma_ctrl_rxchs_state(struct cpdma_ctlr *ctlr)
{
return dma_reg_read(ctlr, CPDMA_RXINTSTATMASKED);
}
+EXPORT_SYMBOL_GPL(cpdma_ctrl_rxchs_state);
u32 cpdma_ctrl_txchs_state(struct cpdma_ctlr *ctlr)
{
return dma_reg_read(ctlr, CPDMA_TXINTSTATMASKED);
}
+EXPORT_SYMBOL_GPL(cpdma_ctrl_txchs_state);
static void cpdma_chan_set_descs(struct cpdma_ctlr *ctlr,
int rx, int desc_num,
@@ -802,6 +810,7 @@ int cpdma_chan_set_weight(struct cpdma_chan *ch, int weight)
spin_unlock_irqrestore(&ctlr->lock, flags);
return ret;
}
+EXPORT_SYMBOL_GPL(cpdma_chan_set_weight);
/* cpdma_chan_get_min_rate - get minimum allowed rate for channel
* Should be called before cpdma_chan_set_rate.
@@ -816,6 +825,7 @@ u32 cpdma_chan_get_min_rate(struct cpdma_ctlr *ctlr)
return DIV_ROUND_UP(divident, divisor);
}
+EXPORT_SYMBOL_GPL(cpdma_chan_get_min_rate);
/* cpdma_chan_set_rate - limits bandwidth for transmit channel.
* The bandwidth * limited channels have to be in order beginning from lowest.
@@ -860,6 +870,7 @@ int cpdma_chan_set_rate(struct cpdma_chan *ch, u32 rate)
spin_unlock_irqrestore(&ctlr->lock, flags);
return ret;
}
+EXPORT_SYMBOL_GPL(cpdma_chan_set_rate);
u32 cpdma_chan_get_rate(struct cpdma_chan *ch)
{
@@ -872,6 +883,7 @@ u32 cpdma_chan_get_rate(struct cpdma_chan *ch)
return rate;
}
+EXPORT_SYMBOL_GPL(cpdma_chan_get_rate);
struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num,
cpdma_handler_fn handler, int rx_type)
@@ -931,6 +943,7 @@ struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num,
spin_unlock_irqrestore(&ctlr->lock, flags);
return chan;
}
+EXPORT_SYMBOL_GPL(cpdma_chan_create);
int cpdma_chan_get_rx_buf_num(struct cpdma_chan *chan)
{
@@ -943,6 +956,7 @@ int cpdma_chan_get_rx_buf_num(struct cpdma_chan *chan)
return desc_num;
}
+EXPORT_SYMBOL_GPL(cpdma_chan_get_rx_buf_num);
int cpdma_chan_destroy(struct cpdma_chan *chan)
{
@@ -964,6 +978,7 @@ int cpdma_chan_destroy(struct cpdma_chan *chan)
spin_unlock_irqrestore(&ctlr->lock, flags);
return 0;
}
+EXPORT_SYMBOL_GPL(cpdma_chan_destroy);
int cpdma_chan_get_stats(struct cpdma_chan *chan,
struct cpdma_chan_stats *stats)
@@ -976,6 +991,7 @@ int cpdma_chan_get_stats(struct cpdma_chan *chan,
spin_unlock_irqrestore(&chan->lock, flags);
return 0;
}
+EXPORT_SYMBOL_GPL(cpdma_chan_get_stats);
static void __cpdma_chan_submit(struct cpdma_chan *chan,
struct cpdma_desc __iomem *desc)
@@ -1100,6 +1116,7 @@ int cpdma_chan_idle_submit(struct cpdma_chan *chan, void *token, void *data,
spin_unlock_irqrestore(&chan->lock, flags);
return ret;
}
+EXPORT_SYMBOL_GPL(cpdma_chan_idle_submit);
int cpdma_chan_idle_submit_mapped(struct cpdma_chan *chan, void *token,
dma_addr_t data, int len, int directed)
@@ -1125,6 +1142,7 @@ int cpdma_chan_idle_submit_mapped(struct cpdma_chan *chan, void *token,
spin_unlock_irqrestore(&chan->lock, flags);
return ret;
}
+EXPORT_SYMBOL_GPL(cpdma_chan_idle_submit_mapped);
int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
int len, int directed)
@@ -1150,6 +1168,7 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
spin_unlock_irqrestore(&chan->lock, flags);
return ret;
}
+EXPORT_SYMBOL_GPL(cpdma_chan_submit);
int cpdma_chan_submit_mapped(struct cpdma_chan *chan, void *token,
dma_addr_t data, int len, int directed)
@@ -1175,6 +1194,7 @@ int cpdma_chan_submit_mapped(struct cpdma_chan *chan, void *token,
spin_unlock_irqrestore(&chan->lock, flags);
return ret;
}
+EXPORT_SYMBOL_GPL(cpdma_chan_submit_mapped);
bool cpdma_check_free_tx_desc(struct cpdma_chan *chan)
{
@@ -1189,6 +1209,7 @@ bool cpdma_check_free_tx_desc(struct cpdma_chan *chan)
spin_unlock_irqrestore(&chan->lock, flags);
return free_tx_desc;
}
+EXPORT_SYMBOL_GPL(cpdma_check_free_tx_desc);
static void __cpdma_chan_free(struct cpdma_chan *chan,
struct cpdma_desc __iomem *desc,
@@ -1289,6 +1310,7 @@ int cpdma_chan_process(struct cpdma_chan *chan, int quota)
}
return used;
}
+EXPORT_SYMBOL_GPL(cpdma_chan_process);
int cpdma_chan_start(struct cpdma_chan *chan)
{
@@ -1308,6 +1330,7 @@ int cpdma_chan_start(struct cpdma_chan *chan)
return 0;
}
+EXPORT_SYMBOL_GPL(cpdma_chan_start);
int cpdma_chan_stop(struct cpdma_chan *chan)
{
@@ -1370,6 +1393,7 @@ int cpdma_chan_stop(struct cpdma_chan *chan)
spin_unlock_irqrestore(&chan->lock, flags);
return 0;
}
+EXPORT_SYMBOL_GPL(cpdma_chan_stop);
int cpdma_chan_int_ctrl(struct cpdma_chan *chan, bool enable)
{
@@ -1416,11 +1440,13 @@ int cpdma_get_num_rx_descs(struct cpdma_ctlr *ctlr)
{
return ctlr->num_rx_desc;
}
+EXPORT_SYMBOL_GPL(cpdma_get_num_rx_descs);
int cpdma_get_num_tx_descs(struct cpdma_ctlr *ctlr)
{
return ctlr->num_tx_desc;
}
+EXPORT_SYMBOL_GPL(cpdma_get_num_tx_descs);
int cpdma_set_num_rx_descs(struct cpdma_ctlr *ctlr, int num_rx_desc)
{
@@ -1442,3 +1468,4 @@ int cpdma_set_num_rx_descs(struct cpdma_ctlr *ctlr, int num_rx_desc)
return ret;
}
+EXPORT_SYMBOL_GPL(cpdma_set_num_rx_descs);
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 885992951e8a..c8b2dc5c1bec 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -391,7 +391,6 @@ static void sixpack_receive_buf(struct tty_struct *tty, const u8 *cp,
const u8 *fp, size_t count)
{
struct sixpack *sp;
- size_t count1;
if (!count)
return;
@@ -401,16 +400,16 @@ static void sixpack_receive_buf(struct tty_struct *tty, const u8 *cp,
return;
/* Read the characters out of the buffer */
- count1 = count;
- while (count) {
- count--;
+ while (count--) {
if (fp && *fp++) {
if (!test_and_set_bit(SIXPF_ERROR, &sp->flags))
sp->dev->stats.rx_errors++;
+ cp++;
continue;
}
+ sixpack_decode(sp, cp, 1);
+ cp++;
}
- sixpack_decode(sp, cp, count1);
tty_unthrottle(tty);
}
diff --git a/drivers/net/ipa/gsi.c b/drivers/net/ipa/gsi.c
index 4c3227e77898..624649484d62 100644
--- a/drivers/net/ipa/gsi.c
+++ b/drivers/net/ipa/gsi.c
@@ -2044,6 +2044,7 @@ static int gsi_ring_setup(struct gsi *gsi)
count = reg_decode(reg, NUM_EV_PER_EE, val);
} else {
reg = gsi_reg(gsi, HW_PARAM_4);
+ val = ioread32(gsi->virt + reg_offset(reg));
count = reg_decode(reg, EV_PER_EE, val);
}
if (!count) {
diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c
index edead9c48d1f..216506eeef1f 100644
--- a/drivers/net/ipa/ipa_main.c
+++ b/drivers/net/ipa/ipa_main.c
@@ -361,7 +361,7 @@ static void ipa_qtime_config(struct ipa *ipa)
{
const struct reg *reg;
u32 offset;
- u32 val;
+ u32 val = 0;
/* Timer clock divider must be disabled when we change the rate */
reg = ipa_reg(ipa, TIMERS_XO_CLK_DIV_CFG);
@@ -374,8 +374,8 @@ static void ipa_qtime_config(struct ipa *ipa)
val |= reg_bit(reg, DPL_TIMESTAMP_SEL);
}
/* Configure tag and NAT Qtime timestamp resolution as well */
- val = reg_encode(reg, TAG_TIMESTAMP_LSB, TAG_TIMESTAMP_SHIFT);
- val = reg_encode(reg, NAT_TIMESTAMP_LSB, NAT_TIMESTAMP_SHIFT);
+ val |= reg_encode(reg, TAG_TIMESTAMP_LSB, TAG_TIMESTAMP_SHIFT);
+ val |= reg_encode(reg, NAT_TIMESTAMP_LSB, NAT_TIMESTAMP_SHIFT);
iowrite32(val, ipa->reg_virt + reg_offset(reg));
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index f6cad0746a02..6147ee8b1d78 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -2584,7 +2584,9 @@ static void macsec_inherit_tso_max(struct net_device *dev)
netif_inherit_tso_max(dev, macsec->real_dev);
}
-static int macsec_update_offload(struct net_device *dev, enum macsec_offload offload)
+static int macsec_update_offload(struct net_device *dev,
+ enum macsec_offload offload,
+ struct netlink_ext_ack *extack)
{
enum macsec_offload prev_offload;
const struct macsec_ops *ops;
@@ -2616,14 +2618,35 @@ static int macsec_update_offload(struct net_device *dev, enum macsec_offload off
if (!ops)
return -EOPNOTSUPP;
- macsec->offload = offload;
-
ctx.secy = &macsec->secy;
ret = offload == MACSEC_OFFLOAD_OFF ? macsec_offload(ops->mdo_del_secy, &ctx)
: macsec_offload(ops->mdo_add_secy, &ctx);
- if (ret) {
- macsec->offload = prev_offload;
+ if (ret)
return ret;
+
+ /* Remove VLAN filters when disabling offload. */
+ if (offload == MACSEC_OFFLOAD_OFF) {
+ vlan_drop_rx_ctag_filter_info(dev);
+ vlan_drop_rx_stag_filter_info(dev);
+ }
+ macsec->offload = offload;
+ /* Add VLAN filters when enabling offload. */
+ if (prev_offload == MACSEC_OFFLOAD_OFF) {
+ ret = vlan_get_rx_ctag_filter_info(dev);
+ if (ret) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "adding ctag VLAN filters failed, err %d",
+ ret);
+ goto rollback_offload;
+ }
+ ret = vlan_get_rx_stag_filter_info(dev);
+ if (ret) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "adding stag VLAN filters failed, err %d",
+ ret);
+ vlan_drop_rx_ctag_filter_info(dev);
+ goto rollback_offload;
+ }
}
macsec_set_head_tail_room(dev);
@@ -2633,6 +2656,12 @@ static int macsec_update_offload(struct net_device *dev, enum macsec_offload off
netdev_update_features(dev);
+ return 0;
+
+rollback_offload:
+ macsec->offload = prev_offload;
+ macsec_offload(ops->mdo_del_secy, &ctx);
+
return ret;
}
@@ -2673,7 +2702,7 @@ static int macsec_upd_offload(struct sk_buff *skb, struct genl_info *info)
offload = nla_get_u8(tb_offload[MACSEC_OFFLOAD_ATTR_TYPE]);
if (macsec->offload != offload)
- ret = macsec_update_offload(dev, offload);
+ ret = macsec_update_offload(dev, offload, info->extack);
out:
rtnl_unlock();
return ret;
@@ -3486,7 +3515,8 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
}
#define MACSEC_FEATURES \
- (NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST)
+ (NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
+ NETIF_F_HW_VLAN_STAG_FILTER | NETIF_F_HW_VLAN_CTAG_FILTER)
#define MACSEC_OFFLOAD_FEATURES \
(MACSEC_FEATURES | NETIF_F_GSO_SOFTWARE | NETIF_F_SOFT_FEATURES | \
@@ -3707,6 +3737,29 @@ static int macsec_set_mac_address(struct net_device *dev, void *p)
return err;
}
+static int macsec_vlan_rx_add_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
+{
+ struct macsec_dev *macsec = netdev_priv(dev);
+
+ if (!macsec_is_offloaded(macsec))
+ return 0;
+
+ return vlan_vid_add(macsec->real_dev, proto, vid);
+}
+
+static int macsec_vlan_rx_kill_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
+{
+ struct macsec_dev *macsec = netdev_priv(dev);
+
+ if (!macsec_is_offloaded(macsec))
+ return 0;
+
+ vlan_vid_del(macsec->real_dev, proto, vid);
+ return 0;
+}
+
static int macsec_change_mtu(struct net_device *dev, int new_mtu)
{
struct macsec_dev *macsec = macsec_priv(dev);
@@ -3748,6 +3801,8 @@ static const struct net_device_ops macsec_netdev_ops = {
.ndo_set_rx_mode = macsec_dev_set_rx_mode,
.ndo_change_rx_flags = macsec_dev_change_rx_flags,
.ndo_set_mac_address = macsec_set_mac_address,
+ .ndo_vlan_rx_add_vid = macsec_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = macsec_vlan_rx_kill_vid,
.ndo_start_xmit = macsec_start_xmit,
.ndo_get_stats64 = macsec_get_stats64,
.ndo_get_iflink = macsec_get_iflink,
@@ -3912,7 +3967,7 @@ static int macsec_changelink(struct net_device *dev, struct nlattr *tb[],
offload = nla_get_u8(data[IFLA_MACSEC_OFFLOAD]);
if (macsec->offload != offload) {
macsec_offload_state_change = true;
- ret = macsec_update_offload(dev, offload);
+ ret = macsec_update_offload(dev, offload, extack);
if (ret)
goto cleanup;
}
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index a71f058eceef..3073d67d0dff 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -352,6 +352,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port,
const struct macvlan_dev *src,
struct sk_buff *skb)
{
+ u32 bc_queue_len_used = READ_ONCE(port->bc_queue_len_used);
struct sk_buff *nskb;
int err = -ENOMEM;
@@ -362,7 +363,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port,
MACVLAN_SKB_CB(nskb)->src = src;
spin_lock(&port->bc_queue.lock);
- if (skb_queue_len(&port->bc_queue) < port->bc_queue_len_used) {
+ if (skb_queue_len(&port->bc_queue) < bc_queue_len_used) {
if (src)
dev_hold(src->dev);
__skb_queue_tail(&port->bc_queue, nskb);
@@ -1681,6 +1682,7 @@ static size_t macvlan_get_size(const struct net_device *dev)
+ macvlan_get_size_mac(vlan) /* IFLA_MACVLAN_MACADDR */
+ nla_total_size(4) /* IFLA_MACVLAN_BC_QUEUE_LEN */
+ nla_total_size(4) /* IFLA_MACVLAN_BC_QUEUE_LEN_USED */
+ + nla_total_size(4) /* IFLA_MACVLAN_BC_CUTOFF */
);
}
@@ -1727,7 +1729,8 @@ static int macvlan_fill_info(struct sk_buff *skb,
}
if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN, vlan->bc_queue_len_req))
goto nla_put_failure;
- if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED, port->bc_queue_len_used))
+ if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED,
+ READ_ONCE(port->bc_queue_len_used)))
goto nla_put_failure;
if (port->bc_cutoff != 1 &&
nla_put_s32(skb, IFLA_MACVLAN_BC_CUTOFF, port->bc_cutoff))
@@ -1787,7 +1790,7 @@ static void update_port_bc_queue_len(struct macvlan_port *port)
if (vlan->bc_queue_len_req > max_bc_queue_len_req)
max_bc_queue_len_req = vlan->bc_queue_len_req;
}
- port->bc_queue_len_used = max_bc_queue_len_req;
+ WRITE_ONCE(port->bc_queue_len_used, max_bc_queue_len_req);
}
static int macvlan_device_event(struct notifier_block *unused,
diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c
index 15fe4d1163c1..ee2913758e54 100644
--- a/drivers/net/mctp/mctp-i2c.c
+++ b/drivers/net/mctp/mctp-i2c.c
@@ -496,8 +496,6 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)
u8 *pecp;
int rc;
- fs = mctp_i2c_get_tx_flow_state(midev, skb);
-
hdr = (void *)skb_mac_header(skb);
/* Sanity check that packet contents matches skb length,
* and can't exceed MCTP_I2C_BUFSZ
@@ -509,6 +507,8 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)
return;
}
+ fs = mctp_i2c_get_tx_flow_state(midev, skb);
+
if (skb_tailroom(skb) >= 1) {
/* Linear case with space, we can just append the PEC */
skb_put(skb, 1);
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 205384dab89a..57dd6821a8aa 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -752,7 +752,7 @@ static ssize_t enabled_store(struct config_item *item,
unregister_netcons_consoles();
}
- ret = strnlen(buf, count);
+ ret = count;
/* Deferred cleanup */
netconsole_process_cleanups();
out_unlock:
@@ -781,7 +781,7 @@ static ssize_t release_store(struct config_item *item, const char *buf,
nt->release = release;
- ret = strnlen(buf, count);
+ ret = count;
out_unlock:
dynamic_netconsole_mutex_unlock();
return ret;
@@ -807,7 +807,7 @@ static ssize_t extended_store(struct config_item *item, const char *buf,
goto out_unlock;
nt->extended = extended;
- ret = strnlen(buf, count);
+ ret = count;
out_unlock:
dynamic_netconsole_mutex_unlock();
return ret;
@@ -817,6 +817,13 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf,
size_t count)
{
struct netconsole_target *nt = to_target(item);
+ size_t len = count;
+
+ /* Account for a trailing newline appended by tools like echo */
+ if (len && buf[len - 1] == '\n')
+ len--;
+ if (len >= IFNAMSIZ)
+ return -ENAMETOOLONG;
dynamic_netconsole_mutex_lock();
if (nt->state == STATE_ENABLED) {
@@ -830,7 +837,7 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf,
trim_newline(nt->np.dev_name, IFNAMSIZ);
dynamic_netconsole_mutex_unlock();
- return strnlen(buf, count);
+ return count;
}
static ssize_t local_port_store(struct config_item *item, const char *buf,
@@ -849,7 +856,7 @@ static ssize_t local_port_store(struct config_item *item, const char *buf,
ret = kstrtou16(buf, 10, &nt->np.local_port);
if (ret < 0)
goto out_unlock;
- ret = strnlen(buf, count);
+ ret = count;
out_unlock:
dynamic_netconsole_mutex_unlock();
return ret;
@@ -871,7 +878,7 @@ static ssize_t remote_port_store(struct config_item *item,
ret = kstrtou16(buf, 10, &nt->np.remote_port);
if (ret < 0)
goto out_unlock;
- ret = strnlen(buf, count);
+ ret = count;
out_unlock:
dynamic_netconsole_mutex_unlock();
return ret;
@@ -896,7 +903,7 @@ static ssize_t local_ip_store(struct config_item *item, const char *buf,
goto out_unlock;
nt->np.ipv6 = !!ipv6;
- ret = strnlen(buf, count);
+ ret = count;
out_unlock:
dynamic_netconsole_mutex_unlock();
return ret;
@@ -921,7 +928,7 @@ static ssize_t remote_ip_store(struct config_item *item, const char *buf,
goto out_unlock;
nt->np.ipv6 = !!ipv6;
- ret = strnlen(buf, count);
+ ret = count;
out_unlock:
dynamic_netconsole_mutex_unlock();
return ret;
@@ -957,7 +964,7 @@ static ssize_t remote_mac_store(struct config_item *item, const char *buf,
goto out_unlock;
memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN);
- ret = strnlen(buf, count);
+ ret = count;
out_unlock:
dynamic_netconsole_mutex_unlock();
return ret;
@@ -1072,26 +1079,30 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf,
size_t count)
{
struct userdatum *udm = to_userdatum(item);
+ char old_value[MAX_EXTRADATA_VALUE_LEN];
struct netconsole_target *nt;
struct userdata *ud;
ssize_t ret;
- if (count > MAX_EXTRADATA_VALUE_LEN)
+ if (count >= MAX_EXTRADATA_VALUE_LEN)
return -EMSGSIZE;
mutex_lock(&netconsole_subsys.su_mutex);
dynamic_netconsole_mutex_lock();
-
- ret = strscpy(udm->value, buf, sizeof(udm->value));
- if (ret < 0)
- goto out_unlock;
+ /* Snapshot for rollback if update_userdata() fails below */
+ strscpy(old_value, udm->value, sizeof(old_value));
+ /* count is bounded above, so strscpy() cannot truncate here */
+ strscpy(udm->value, buf, sizeof(udm->value));
trim_newline(udm->value, sizeof(udm->value));
ud = to_userdata(item->ci_parent);
nt = userdata_to_target(ud);
ret = update_userdata(nt);
- if (ret < 0)
+ if (ret < 0) {
+ /* Restore the previous value so it matches the live payload */
+ strscpy(udm->value, old_value, sizeof(udm->value));
goto out_unlock;
+ }
ret = count;
out_unlock:
dynamic_netconsole_mutex_unlock();
@@ -1133,7 +1144,7 @@ static ssize_t sysdata_msgid_enabled_store(struct config_item *item,
disable_sysdata_feature(nt, SYSDATA_MSGID);
unlock_ok:
- ret = strnlen(buf, count);
+ ret = count;
dynamic_netconsole_mutex_unlock();
mutex_unlock(&netconsole_subsys.su_mutex);
return ret;
@@ -1162,7 +1173,7 @@ static ssize_t sysdata_release_enabled_store(struct config_item *item,
disable_sysdata_feature(nt, SYSDATA_RELEASE);
unlock_ok:
- ret = strnlen(buf, count);
+ ret = count;
dynamic_netconsole_mutex_unlock();
mutex_unlock(&netconsole_subsys.su_mutex);
return ret;
@@ -1191,7 +1202,7 @@ static ssize_t sysdata_taskname_enabled_store(struct config_item *item,
disable_sysdata_feature(nt, SYSDATA_TASKNAME);
unlock_ok:
- ret = strnlen(buf, count);
+ ret = count;
dynamic_netconsole_mutex_unlock();
mutex_unlock(&netconsole_subsys.su_mutex);
return ret;
@@ -1225,7 +1236,7 @@ static ssize_t sysdata_cpu_nr_enabled_store(struct config_item *item,
disable_sysdata_feature(nt, SYSDATA_CPU_NR);
unlock_ok:
- ret = strnlen(buf, count);
+ ret = count;
dynamic_netconsole_mutex_unlock();
mutex_unlock(&netconsole_subsys.su_mutex);
return ret;
diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c
index e82de0fd3157..8f6d0a09e176 100644
--- a/drivers/net/netdevsim/dev.c
+++ b/drivers/net/netdevsim/dev.c
@@ -829,7 +829,7 @@ static struct sk_buff *nsim_dev_trap_skb_build(void)
skb->protocol = htons(ETH_P_IP);
skb_set_network_header(skb, skb->len);
- iph = skb_put(skb, sizeof(struct iphdr));
+ iph = skb_put_zero(skb, sizeof(struct iphdr));
iph->protocol = IPPROTO_UDP;
iph->saddr = in_aton("192.0.2.1");
iph->daddr = in_aton("198.51.100.1");
diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c
index 1f381d7b13ff..96a7d255f50f 100644
--- a/drivers/net/phy/dp83869.c
+++ b/drivers/net/phy/dp83869.c
@@ -31,6 +31,7 @@
#define DP83869_RGMIICTL 0x0032
#define DP83869_STRAP_STS1 0x006e
#define DP83869_RGMIIDCTL 0x0086
+#define DP83869_ANA_PLL_PROG_PI 0x00c6
#define DP83869_RXFCFG 0x0134
#define DP83869_RXFPMD1 0x0136
#define DP83869_RXFPMD2 0x0137
@@ -826,12 +827,22 @@ static int dp83869_config_init(struct phy_device *phydev)
dp83869_config_port_mirroring(phydev);
/* Clock output selection if muxing property is set */
- if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK)
+ if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) {
+ /*
+ * Table 7-121 in datasheet says we have to set register 0xc6
+ * to value 0x10 before CLK_O_SEL can be modified.
+ */
+ ret = phy_write_mmd(phydev, DP83869_DEVADDR,
+ DP83869_ANA_PLL_PROG_PI, 0x10);
+ if (ret)
+ return ret;
+
ret = phy_modify_mmd(phydev,
DP83869_DEVADDR, DP83869_IO_MUX_CFG,
DP83869_IO_MUX_CFG_CLK_O_SEL_MASK,
dp83869->clk_output_sel <<
DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT);
+ }
if (phy_interface_is_rgmii(phydev)) {
ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIIDCTL,
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 3bd415710bf3..f3696d9819d3 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -927,8 +927,8 @@ static int get_phy_c45_ids(struct mii_bus *bus, int addr,
/* returning -ENODEV doesn't stop bus
* scanning
*/
- return (phy_reg == -EIO ||
- phy_reg == -ENODEV) ? -ENODEV : -EIO;
+ return (ret == -EIO ||
+ ret == -ENODEV) ? -ENODEV : -EIO;
if (!ret)
continue;
diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c
index 2995b08bac96..63726cf98cd4 100644
--- a/drivers/net/phy/qcom/at803x.c
+++ b/drivers/net/phy/qcom/at803x.c
@@ -524,7 +524,7 @@ static int at803x_config_init(struct phy_device *phydev)
* behaviour but we still need to accommodate it. XNP is only needed
* for 10Gbps support, so disable XNP.
*/
- return phy_modify(phydev, MII_ADVERTISE, MDIO_AN_CTRL1_XNP, 0);
+ return phy_modify(phydev, MII_ADVERTISE, ADVERTISE_XNP, 0);
}
static void at803x_link_change_notify(struct phy_device *phydev)
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index e9b41777be80..192a5b94783e 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -1057,6 +1057,9 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
struct ppp_net *pn;
int __user *p = (int __user *)arg;
+ if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+ return -EPERM;
+
switch (cmd) {
case PPPIOCNEWUNIT:
/* Create a new ppp unit */
@@ -2257,7 +2260,7 @@ ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
*/
static void __ppp_decompress_proto(struct sk_buff *skb)
{
- if (skb->data[0] & 0x01)
+ if (ppp_skb_is_compressed_proto(skb))
*(u8 *)skb_push(skb, 1) = 0x00;
}
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index 4275b393a454..6992b3f64781 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -424,7 +424,7 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev,
if (skb_mac_header_len(skb) < ETH_HLEN)
goto drop;
- if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
+ if (!pskb_may_pull(skb, PPPOE_SES_HLEN))
goto drop;
ph = pppoe_hdr(skb);
@@ -434,6 +434,12 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev,
if (skb->len < len)
goto drop;
+ /* skb->data points to the PPP protocol header after skb_pull_rcsum.
+ * Drop PFC frames.
+ */
+ if (ppp_skb_is_compressed_proto(skb))
+ goto drop;
+
if (pskb_trim_rcsum(skb, len))
goto drop;
diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c
index e3c785da3eef..1a9b27d5e256 100644
--- a/drivers/net/slip/slhc.c
+++ b/drivers/net/slip/slhc.c
@@ -80,9 +80,9 @@
#include <linux/unaligned.h>
static unsigned char *encode(unsigned char *cp, unsigned short n);
-static long decode(unsigned char **cpp);
+static long decode(unsigned char **cpp, const unsigned char *end);
static unsigned char * put16(unsigned char *cp, unsigned short x);
-static unsigned short pull16(unsigned char **cpp);
+static long pull16(unsigned char **cpp, const unsigned char *end);
/* Allocate compression data structure
* slots must be in range 0 to 255 (zero meaning no compression)
@@ -190,30 +190,34 @@ encode(unsigned char *cp, unsigned short n)
return cp;
}
-/* Pull a 16-bit integer in host order from buffer in network byte order */
-static unsigned short
-pull16(unsigned char **cpp)
+/* Pull a 16-bit integer in host order from buffer in network byte order.
+ * Returns -1 if the buffer is exhausted, otherwise the 16-bit value.
+ */
+static long
+pull16(unsigned char **cpp, const unsigned char *end)
{
- short rval;
+ long rval;
+ if (*cpp + 2 > end)
+ return -1;
rval = *(*cpp)++;
rval <<= 8;
rval |= *(*cpp)++;
return rval;
}
-/* Decode a number */
+/* Decode a number. Returns -1 if the buffer is exhausted. */
static long
-decode(unsigned char **cpp)
+decode(unsigned char **cpp, const unsigned char *end)
{
int x;
+ if (*cpp >= end)
+ return -1;
x = *(*cpp)++;
- if(x == 0){
- return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */
- } else {
- return x & 0xff; /* -1 if PULLCHAR returned error */
- }
+ if (x == 0)
+ return pull16(cpp, end);
+ return x & 0xff;
}
/*
@@ -499,6 +503,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
struct cstate *cs;
int len, hdrlen;
unsigned char *cp = icp;
+ const unsigned char *end = icp + isize;
/* We've got a compressed packet; read the change byte */
comp->sls_i_compressed++;
@@ -506,6 +511,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
comp->sls_i_error++;
return 0;
}
+ if (!comp->rstate)
+ goto bad;
changes = *cp++;
if(changes & NEW_C){
/* Make sure the state index is in range, then grab the state.
@@ -534,6 +541,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
thp = &cs->cs_tcp;
ip = &cs->cs_ip;
+ if (cp + 2 > end)
+ goto bad;
thp->check = *(__sum16 *)cp;
cp += 2;
@@ -564,26 +573,26 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
default:
if(changes & NEW_U){
thp->urg = 1;
- if((x = decode(&cp)) == -1) {
+ if((x = decode(&cp, end)) == -1) {
goto bad;
}
thp->urg_ptr = htons(x);
} else
thp->urg = 0;
if(changes & NEW_W){
- if((x = decode(&cp)) == -1) {
+ if((x = decode(&cp, end)) == -1) {
goto bad;
}
thp->window = htons( ntohs(thp->window) + x);
}
if(changes & NEW_A){
- if((x = decode(&cp)) == -1) {
+ if((x = decode(&cp, end)) == -1) {
goto bad;
}
thp->ack_seq = htonl( ntohl(thp->ack_seq) + x);
}
if(changes & NEW_S){
- if((x = decode(&cp)) == -1) {
+ if((x = decode(&cp, end)) == -1) {
goto bad;
}
thp->seq = htonl( ntohl(thp->seq) + x);
@@ -591,7 +600,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
break;
}
if(changes & NEW_I){
- if((x = decode(&cp)) == -1) {
+ if((x = decode(&cp, end)) == -1) {
goto bad;
}
ip->id = htons (ntohs (ip->id) + x);
@@ -649,6 +658,10 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
struct cstate *cs;
unsigned int ihl;
+ if (!comp->rstate) {
+ comp->sls_i_error++;
+ return slhc_toss(comp);
+ }
/* The packet is shorter than a legal IP header.
* Also make sure isize is positive.
*/
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 0c83bbbea2e7..f69e7e1ab778 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -3890,7 +3890,7 @@ static void r8156_ups_en(struct r8152 *tp, bool enable)
case RTL_VER_15:
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPHY_XTAL);
ocp_data &= ~OOBS_POLLING;
- ocp_write_byte(tp, MCU_TYPE_USB, USB_UPHY_XTAL, ocp_data);
+ ocp_write_word(tp, MCU_TYPE_USB, USB_UPHY_XTAL, ocp_data);
break;
default:
break;
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index 4cda0643afb6..c880c95c41a5 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -683,6 +683,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
rtl8150_t *dev = netdev_priv(netdev);
+ unsigned int skb_len;
int count, res;
/* pad the frame and ensure terminating USB packet, datasheet 9.2.3 */
@@ -694,6 +695,8 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
}
+ skb_len = skb->len;
+
netif_stop_queue(netdev);
dev->tx_skb = skb;
usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2),
@@ -707,9 +710,16 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb,
netdev->stats.tx_errors++;
netif_start_queue(netdev);
}
+ /*
+ * The URB was not submitted, so write_bulk_callback() will
+ * never run to free dev->tx_skb. Drop the skb here and
+ * clear tx_skb to avoid leaving a stale pointer.
+ */
+ dev->tx_skb = NULL;
+ dev_kfree_skb_any(skb);
} else {
netdev->stats.tx_packets++;
- netdev->stats.tx_bytes += skb->len;
+ netdev->stats.tx_bytes += skb_len;
netif_trans_update(netdev);
}
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index c0b9bc5574e2..67b913218144 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -3748,6 +3748,12 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs)
queue_pairs);
return -EINVAL;
}
+
+ /* Keep max_tx_vq in sync so that a later RSS command does not
+ * revert queue_pairs to a stale value.
+ */
+ if (vi->has_rss)
+ vi->rss_trailer.max_tx_vq = cpu_to_le16(queue_pairs);
succ:
vi->curr_queue_pairs = queue_pairs;
if (dev->flags & IFF_UP) {
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 8c009bcaa8e7..91a97c3f46c4 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -1084,6 +1084,7 @@ static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev,
err:
port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE;
+ synchronize_net();
return ret;
}
@@ -1103,10 +1104,16 @@ static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev,
}
/* inverse of do_vrf_add_slave */
-static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev)
+static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev,
+ bool needs_sync)
{
netdev_upper_dev_unlink(port_dev, dev);
port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE;
+ /* Make sure that concurrent RCU readers that identified the device
+ * as a VRF port see a VRF master or no master at all.
+ */
+ if (needs_sync)
+ synchronize_net();
cycle_netdev(port_dev, NULL);
@@ -1115,7 +1122,7 @@ static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev)
static int vrf_del_slave(struct net_device *dev, struct net_device *port_dev)
{
- return do_vrf_del_slave(dev, port_dev);
+ return do_vrf_del_slave(dev, port_dev, true);
}
static void vrf_dev_uninit(struct net_device *dev)
@@ -1669,7 +1676,7 @@ static void vrf_dellink(struct net_device *dev, struct list_head *head)
struct list_head *iter;
netdev_for_each_lower_dev(dev, port_dev, iter)
- vrf_del_slave(dev, port_dev);
+ do_vrf_del_slave(dev, port_dev, false);
vrf_map_unregister_dev(dev);
@@ -1801,7 +1808,7 @@ static int vrf_device_event(struct notifier_block *unused,
goto out;
vrf_dev = netdev_master_upper_dev_get(dev);
- vrf_del_slave(vrf_dev, dev);
+ do_vrf_del_slave(vrf_dev, dev, false);
}
out:
return NOTIFY_DONE;
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index ec8e91707f84..01f2d1fa9d7d 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -3,7 +3,7 @@
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
- * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include "core.h"
#include "debug.h"
@@ -14,6 +14,7 @@
#include "wmi-tlv.h"
#include "p2p.h"
#include "testmode.h"
+#include "txrx.h"
#include <linux/bitfield.h>
/***************/
@@ -224,8 +225,9 @@ static int ath10k_wmi_tlv_parse_peer_stats_info(struct ath10k *ar, u16 tag, u16
const void *ptr, void *data)
{
const struct wmi_tlv_peer_stats_info *stat = ptr;
- struct ieee80211_sta *sta;
+ u32 vdev_id = *(u32 *)data;
struct ath10k_sta *arsta;
+ struct ath10k_peer *peer;
if (tag != WMI_TLV_TAG_STRUCT_PEER_STATS_INFO)
return -EPROTO;
@@ -241,20 +243,20 @@ static int ath10k_wmi_tlv_parse_peer_stats_info(struct ath10k *ar, u16 tag, u16
__le32_to_cpu(stat->last_tx_rate_code),
__le32_to_cpu(stat->last_tx_bitrate_kbps));
- rcu_read_lock();
- sta = ieee80211_find_sta_by_ifaddr(ar->hw, stat->peer_macaddr.addr, NULL);
- if (!sta) {
- rcu_read_unlock();
- ath10k_warn(ar, "not found station for peer stats\n");
+ guard(spinlock_bh)(&ar->data_lock);
+
+ peer = ath10k_peer_find(ar, vdev_id, stat->peer_macaddr.addr);
+ if (!peer || !peer->sta) {
+ ath10k_warn(ar, "not found %s with vdev id %u mac addr %pM for peer stats\n",
+ peer ? "sta" : "peer", vdev_id, stat->peer_macaddr.addr);
return -EINVAL;
}
- arsta = (struct ath10k_sta *)sta->drv_priv;
+ arsta = (struct ath10k_sta *)peer->sta->drv_priv;
arsta->rx_rate_code = __le32_to_cpu(stat->last_rx_rate_code);
arsta->rx_bitrate_kbps = __le32_to_cpu(stat->last_rx_bitrate_kbps);
arsta->tx_rate_code = __le32_to_cpu(stat->last_tx_rate_code);
arsta->tx_bitrate_kbps = __le32_to_cpu(stat->last_tx_bitrate_kbps);
- rcu_read_unlock();
return 0;
}
@@ -266,6 +268,7 @@ static int ath10k_wmi_tlv_op_pull_peer_stats_info(struct ath10k *ar,
const struct wmi_tlv_peer_stats_info_ev *ev;
const void *data;
u32 num_peer_stats;
+ u32 vdev_id;
int ret;
tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
@@ -284,15 +287,16 @@ static int ath10k_wmi_tlv_op_pull_peer_stats_info(struct ath10k *ar,
}
num_peer_stats = __le32_to_cpu(ev->num_peers);
+ vdev_id = __le32_to_cpu(ev->vdev_id);
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi tlv peer stats info update peer vdev id %d peers %i more data %d\n",
- __le32_to_cpu(ev->vdev_id),
+ vdev_id,
num_peer_stats,
__le32_to_cpu(ev->more_data));
ret = ath10k_wmi_tlv_iter(ar, data, ath10k_wmi_tlv_len(data),
- ath10k_wmi_tlv_parse_peer_stats_info, NULL);
+ ath10k_wmi_tlv_parse_peer_stats_info, &vdev_id);
if (ret)
ath10k_warn(ar, "failed to parse stats info tlv: %d\n", ret);
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index e4ee2ba1f669..c06ee110a90f 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -1557,12 +1557,15 @@ static int ath11k_mac_setup_bcn_tmpl_ema(struct ath11k_vif *arvif,
if (!beacons || !beacons->cnt) {
ath11k_warn(arvif->ar->ab,
"failed to get ema beacon templates from mac80211\n");
- return -EPERM;
+ ret = -EPERM;
+ goto free;
}
if (tx_arvif == arvif) {
- if (ath11k_mac_set_vif_params(tx_arvif, beacons->bcn[0].skb))
- return -EINVAL;
+ if (ath11k_mac_set_vif_params(tx_arvif, beacons->bcn[0].skb)) {
+ ret = -EINVAL;
+ goto free;
+ }
} else {
arvif->wpaie_present = tx_arvif->wpaie_present;
}
@@ -1589,11 +1592,11 @@ static int ath11k_mac_setup_bcn_tmpl_ema(struct ath11k_vif *arvif,
}
}
- ieee80211_beacon_free_ema_list(beacons);
-
if (tx_arvif != arvif && !nontx_vif_params_set)
- return -EINVAL; /* Profile not found in the beacons */
+ ret = -EINVAL; /* Profile not found in the beacons */
+free:
+ ieee80211_beacon_free_ema_list(beacons);
return ret;
}
@@ -1622,19 +1625,22 @@ static int ath11k_mac_setup_bcn_tmpl_mbssid(struct ath11k_vif *arvif,
}
if (tx_arvif == arvif) {
- if (ath11k_mac_set_vif_params(tx_arvif, bcn))
- return -EINVAL;
+ if (ath11k_mac_set_vif_params(tx_arvif, bcn)) {
+ ret = -EINVAL;
+ goto free;
+ }
} else if (!ath11k_mac_set_nontx_vif_params(tx_arvif, arvif, bcn)) {
- return -EINVAL;
+ ret = -EINVAL;
+ goto free;
}
ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn, 0);
- kfree_skb(bcn);
-
if (ret)
ath11k_warn(ab, "failed to submit beacon template command: %d\n",
ret);
+free:
+ kfree_skb(bcn);
return ret;
}
diff --git a/drivers/net/wireless/ath/ath12k/dp_htt.c b/drivers/net/wireless/ath/ath12k/dp_htt.c
index e71bb71a6020..9c19d9707abf 100644
--- a/drivers/net/wireless/ath/ath12k/dp_htt.c
+++ b/drivers/net/wireless/ath/ath12k/dp_htt.c
@@ -205,16 +205,9 @@ ath12k_update_per_peer_tx_stats(struct ath12k_pdev_dp *dp_pdev,
if (!(usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_RATE)))
return;
- if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON)) {
+ if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON))
is_ampdu =
HTT_USR_CMPLTN_IS_AMPDU(usr_stats->cmpltn_cmn.flags);
- tx_retry_failed =
- __le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_tried) -
- __le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_success);
- tx_retry_count =
- HTT_USR_CMPLTN_LONG_RETRY(usr_stats->cmpltn_cmn.flags) +
- HTT_USR_CMPLTN_SHORT_RETRY(usr_stats->cmpltn_cmn.flags);
- }
if (usr_stats->tlv_flags &
BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS)) {
@@ -223,10 +216,19 @@ ath12k_update_per_peer_tx_stats(struct ath12k_pdev_dp *dp_pdev,
HTT_PPDU_STATS_ACK_BA_INFO_NUM_MSDU_M);
tid = le32_get_bits(usr_stats->ack_ba.info,
HTT_PPDU_STATS_ACK_BA_INFO_TID_NUM);
- }
- if (common->fes_duration_us)
- tx_duration = le32_to_cpu(common->fes_duration_us);
+ if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON)) {
+ tx_retry_failed =
+ __le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_tried) -
+ __le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_success);
+ tx_retry_count =
+ HTT_USR_CMPLTN_LONG_RETRY(usr_stats->cmpltn_cmn.flags) +
+ HTT_USR_CMPLTN_SHORT_RETRY(usr_stats->cmpltn_cmn.flags);
+ }
+
+ if (common->fes_duration_us)
+ tx_duration = le32_to_cpu(common->fes_duration_us);
+ }
user_rate = &usr_stats->rate;
flags = HTT_USR_RATE_PREAMBLE(user_rate->rate_flags);
diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h
index 43e3880f8257..bf4f7dbae866 100644
--- a/drivers/net/wireless/ath/ath12k/hal.h
+++ b/drivers/net/wireless/ath/ath12k/hal.h
@@ -268,21 +268,28 @@ enum hal_rx_reception_type {
};
enum hal_rx_legacy_rate {
- HAL_RX_LEGACY_RATE_1_MBPS,
- HAL_RX_LEGACY_RATE_2_MBPS,
- HAL_RX_LEGACY_RATE_5_5_MBPS,
- HAL_RX_LEGACY_RATE_6_MBPS,
- HAL_RX_LEGACY_RATE_9_MBPS,
- HAL_RX_LEGACY_RATE_11_MBPS,
- HAL_RX_LEGACY_RATE_12_MBPS,
- HAL_RX_LEGACY_RATE_18_MBPS,
- HAL_RX_LEGACY_RATE_24_MBPS,
- HAL_RX_LEGACY_RATE_36_MBPS,
- HAL_RX_LEGACY_RATE_48_MBPS,
- HAL_RX_LEGACY_RATE_54_MBPS,
+ HAL_RX_LEGACY_RATE_LP_1_MBPS,
+ HAL_RX_LEGACY_RATE_LP_2_MBPS,
+ HAL_RX_LEGACY_RATE_LP_5_5_MBPS,
+ HAL_RX_LEGACY_RATE_LP_11_MBPS,
+ HAL_RX_LEGACY_RATE_SP_2_MBPS,
+ HAL_RX_LEGACY_RATE_SP_5_5_MBPS,
+ HAL_RX_LEGACY_RATE_SP_11_MBPS,
HAL_RX_LEGACY_RATE_INVALID,
};
+enum hal_rx_legacy_rates_ofdm {
+ HAL_RX_LEGACY_RATE_OFDM_48_MBPS,
+ HAL_RX_LEGACY_RATE_OFDM_24_MBPS,
+ HAL_RX_LEGACY_RATE_OFDM_12_MBPS,
+ HAL_RX_LEGACY_RATE_OFDM_6_MBPS,
+ HAL_RX_LEGACY_RATE_OFDM_54_MBPS,
+ HAL_RX_LEGACY_RATE_OFDM_36_MBPS,
+ HAL_RX_LEGACY_RATE_OFDM_18_MBPS,
+ HAL_RX_LEGACY_RATE_OFDM_9_MBPS,
+ HAL_RX_LEGACY_RATE_OFDM_INVALID,
+};
+
enum hal_ring_type {
HAL_REO_DST,
HAL_REO_EXCEPTION,
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index b253d1e3f405..fa36e984c74b 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -164,30 +164,31 @@ static const struct ieee80211_channel ath12k_6ghz_channels[] = {
CHAN6G(233, 7115, 0),
};
+#define ATH12K_MAC_RATE_A_M(bps, code) \
+ { .bitrate = (bps), .hw_value = (code),\
+ .flags = IEEE80211_RATE_MANDATORY_A }
+
+#define ATH12K_MAC_RATE_B(bps, code, code_short) \
+ { .bitrate = (bps), .hw_value = (code), .hw_value_short = (code_short),\
+ .flags = IEEE80211_RATE_SHORT_PREAMBLE }
+
static struct ieee80211_rate ath12k_legacy_rates[] = {
{ .bitrate = 10,
.hw_value = ATH12K_HW_RATE_CCK_LP_1M },
- { .bitrate = 20,
- .hw_value = ATH12K_HW_RATE_CCK_LP_2M,
- .hw_value_short = ATH12K_HW_RATE_CCK_SP_2M,
- .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 55,
- .hw_value = ATH12K_HW_RATE_CCK_LP_5_5M,
- .hw_value_short = ATH12K_HW_RATE_CCK_SP_5_5M,
- .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 110,
- .hw_value = ATH12K_HW_RATE_CCK_LP_11M,
- .hw_value_short = ATH12K_HW_RATE_CCK_SP_11M,
- .flags = IEEE80211_RATE_SHORT_PREAMBLE },
-
- { .bitrate = 60, .hw_value = ATH12K_HW_RATE_OFDM_6M },
- { .bitrate = 90, .hw_value = ATH12K_HW_RATE_OFDM_9M },
- { .bitrate = 120, .hw_value = ATH12K_HW_RATE_OFDM_12M },
- { .bitrate = 180, .hw_value = ATH12K_HW_RATE_OFDM_18M },
- { .bitrate = 240, .hw_value = ATH12K_HW_RATE_OFDM_24M },
- { .bitrate = 360, .hw_value = ATH12K_HW_RATE_OFDM_36M },
- { .bitrate = 480, .hw_value = ATH12K_HW_RATE_OFDM_48M },
- { .bitrate = 540, .hw_value = ATH12K_HW_RATE_OFDM_54M },
+ ATH12K_MAC_RATE_B(20, ATH12K_HW_RATE_CCK_LP_2M,
+ ATH12K_HW_RATE_CCK_SP_2M),
+ ATH12K_MAC_RATE_B(55, ATH12K_HW_RATE_CCK_LP_5_5M,
+ ATH12K_HW_RATE_CCK_SP_5_5M),
+ ATH12K_MAC_RATE_B(110, ATH12K_HW_RATE_CCK_LP_11M,
+ ATH12K_HW_RATE_CCK_SP_11M),
+ ATH12K_MAC_RATE_A_M(60, ATH12K_HW_RATE_OFDM_6M),
+ ATH12K_MAC_RATE_A_M(90, ATH12K_HW_RATE_OFDM_9M),
+ ATH12K_MAC_RATE_A_M(120, ATH12K_HW_RATE_OFDM_12M),
+ ATH12K_MAC_RATE_A_M(180, ATH12K_HW_RATE_OFDM_18M),
+ ATH12K_MAC_RATE_A_M(240, ATH12K_HW_RATE_OFDM_24M),
+ ATH12K_MAC_RATE_A_M(360, ATH12K_HW_RATE_OFDM_36M),
+ ATH12K_MAC_RATE_A_M(480, ATH12K_HW_RATE_OFDM_48M),
+ ATH12K_MAC_RATE_A_M(540, ATH12K_HW_RATE_OFDM_54M),
};
static const int
@@ -732,11 +733,17 @@ u8 ath12k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
if (ath12k_mac_bitrate_is_cck(rate->bitrate) != cck)
continue;
- if (rate->hw_value == hw_rate)
+ /* To handle 802.11a PPDU type */
+ if ((!cck) && (rate->hw_value == hw_rate) &&
+ (rate->flags & IEEE80211_RATE_MANDATORY_A))
return i;
+ /* To handle 802.11b short PPDU type */
else if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE &&
rate->hw_value_short == hw_rate)
return i;
+ /* To handle 802.11b long PPDU type */
+ else if (rate->hw_value == hw_rate)
+ return i;
}
return 0;
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c
index c9cea597a92e..77f5d23be78d 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c
@@ -405,6 +405,42 @@ ath12k_wifi7_dp_mon_hal_rx_parse_user_info(const struct hal_receive_user_info *r
}
}
+static __always_inline u8
+ath12k_wifi7_hal_mon_map_legacy_rate_to_hw_rate(u8 rate)
+{
+ u8 ath12k_rate;
+
+ /* Map hal_rx_legacy_rate to ath12k_hw_rate_cck */
+ switch (rate) {
+ case HAL_RX_LEGACY_RATE_LP_1_MBPS:
+ ath12k_rate = ATH12K_HW_RATE_CCK_LP_1M;
+ break;
+ case HAL_RX_LEGACY_RATE_LP_2_MBPS:
+ ath12k_rate = ATH12K_HW_RATE_CCK_LP_2M;
+ break;
+ case HAL_RX_LEGACY_RATE_LP_5_5_MBPS:
+ ath12k_rate = ATH12K_HW_RATE_CCK_LP_5_5M;
+ break;
+ case HAL_RX_LEGACY_RATE_LP_11_MBPS:
+ ath12k_rate = ATH12K_HW_RATE_CCK_LP_11M;
+ break;
+ case HAL_RX_LEGACY_RATE_SP_2_MBPS:
+ ath12k_rate = ATH12K_HW_RATE_CCK_SP_2M;
+ break;
+ case HAL_RX_LEGACY_RATE_SP_5_5_MBPS:
+ ath12k_rate = ATH12K_HW_RATE_CCK_SP_5_5M;
+ break;
+ case HAL_RX_LEGACY_RATE_SP_11_MBPS:
+ ath12k_rate = ATH12K_HW_RATE_CCK_SP_11M;
+ break;
+ default:
+ ath12k_rate = rate;
+ break;
+ }
+
+ return ath12k_rate;
+}
+
static void
ath12k_wifi7_dp_mon_parse_l_sig_b(const struct hal_rx_lsig_b_info *lsigb,
struct hal_rx_mon_ppdu_info *ppdu_info)
@@ -415,25 +451,32 @@ ath12k_wifi7_dp_mon_parse_l_sig_b(const struct hal_rx_lsig_b_info *lsigb,
rate = u32_get_bits(info0, HAL_RX_LSIG_B_INFO_INFO0_RATE);
switch (rate) {
case 1:
- rate = HAL_RX_LEGACY_RATE_1_MBPS;
+ rate = HAL_RX_LEGACY_RATE_LP_1_MBPS;
break;
case 2:
- case 5:
- rate = HAL_RX_LEGACY_RATE_2_MBPS;
+ rate = HAL_RX_LEGACY_RATE_LP_2_MBPS;
break;
case 3:
- case 6:
- rate = HAL_RX_LEGACY_RATE_5_5_MBPS;
+ rate = HAL_RX_LEGACY_RATE_LP_5_5_MBPS;
break;
case 4:
+ rate = HAL_RX_LEGACY_RATE_LP_11_MBPS;
+ break;
+ case 5:
+ rate = HAL_RX_LEGACY_RATE_SP_2_MBPS;
+ break;
+ case 6:
+ rate = HAL_RX_LEGACY_RATE_SP_5_5_MBPS;
+ break;
case 7:
- rate = HAL_RX_LEGACY_RATE_11_MBPS;
+ rate = HAL_RX_LEGACY_RATE_SP_11_MBPS;
break;
default:
rate = HAL_RX_LEGACY_RATE_INVALID;
+ break;
}
- ppdu_info->rate = rate;
+ ppdu_info->rate = ath12k_wifi7_hal_mon_map_legacy_rate_to_hw_rate(rate);
ppdu_info->cck_flag = 1;
}
@@ -447,31 +490,32 @@ ath12k_wifi7_dp_mon_parse_l_sig_a(const struct hal_rx_lsig_a_info *lsiga,
rate = u32_get_bits(info0, HAL_RX_LSIG_A_INFO_INFO0_RATE);
switch (rate) {
case 8:
- rate = HAL_RX_LEGACY_RATE_48_MBPS;
+ rate = HAL_RX_LEGACY_RATE_OFDM_48_MBPS;
break;
case 9:
- rate = HAL_RX_LEGACY_RATE_24_MBPS;
+ rate = HAL_RX_LEGACY_RATE_OFDM_24_MBPS;
break;
case 10:
- rate = HAL_RX_LEGACY_RATE_12_MBPS;
+ rate = HAL_RX_LEGACY_RATE_OFDM_12_MBPS;
break;
case 11:
- rate = HAL_RX_LEGACY_RATE_6_MBPS;
+ rate = HAL_RX_LEGACY_RATE_OFDM_6_MBPS;
break;
case 12:
- rate = HAL_RX_LEGACY_RATE_54_MBPS;
+ rate = HAL_RX_LEGACY_RATE_OFDM_54_MBPS;
break;
case 13:
- rate = HAL_RX_LEGACY_RATE_36_MBPS;
+ rate = HAL_RX_LEGACY_RATE_OFDM_36_MBPS;
break;
case 14:
- rate = HAL_RX_LEGACY_RATE_18_MBPS;
+ rate = HAL_RX_LEGACY_RATE_OFDM_18_MBPS;
break;
case 15:
- rate = HAL_RX_LEGACY_RATE_9_MBPS;
+ rate = HAL_RX_LEGACY_RATE_OFDM_9_MBPS;
break;
default:
- rate = HAL_RX_LEGACY_RATE_INVALID;
+ rate = HAL_RX_LEGACY_RATE_OFDM_INVALID;
+ break;
}
ppdu_info->rate = rate;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
index a790f1693b82..4adc0d0e4251 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
@@ -1007,18 +1007,33 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci)
core = brcmf_chip_add_core(ci, BCMA_CORE_CHIPCOMMON,
SI_ENUM_BASE_DEFAULT, 0);
+ if (IS_ERR(core))
+ return PTR_ERR(core);
+
brcmf_chip_sb_corerev(ci, core);
core = brcmf_chip_add_core(ci, BCMA_CORE_SDIO_DEV,
BCM4329_CORE_BUS_BASE, 0);
+ if (IS_ERR(core))
+ return PTR_ERR(core);
+
brcmf_chip_sb_corerev(ci, core);
core = brcmf_chip_add_core(ci, BCMA_CORE_INTERNAL_MEM,
BCM4329_CORE_SOCRAM_BASE, 0);
+ if (IS_ERR(core))
+ return PTR_ERR(core);
+
brcmf_chip_sb_corerev(ci, core);
core = brcmf_chip_add_core(ci, BCMA_CORE_ARM_CM3,
BCM4329_CORE_ARM_BASE, 0);
+ if (IS_ERR(core))
+ return PTR_ERR(core);
+
brcmf_chip_sb_corerev(ci, core);
core = brcmf_chip_add_core(ci, BCMA_CORE_80211, 0x18001000, 0);
+ if (IS_ERR(core))
+ return PTR_ERR(core);
+
brcmf_chip_sb_corerev(ci, core);
} else if (socitype == SOCI_AI) {
ci->iscoreup = brcmf_chip_ai_iscoreup;
diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c
index 8a6bf1365cfa..d3b9f7619a1a 100644
--- a/drivers/net/wireless/marvell/libertas/if_usb.c
+++ b/drivers/net/wireless/marvell/libertas/if_usb.c
@@ -114,8 +114,8 @@ static void if_usb_write_bulk_callback(struct urb *urb)
static void if_usb_free(struct if_usb_card *cardp)
{
/* Unlink tx & rx urb */
- usb_kill_urb(cardp->tx_urb);
- usb_kill_urb(cardp->rx_urb);
+ usb_kill_anchored_urbs(&cardp->tx_submitted);
+ usb_kill_anchored_urbs(&cardp->rx_submitted);
usb_free_urb(cardp->tx_urb);
cardp->tx_urb = NULL;
@@ -221,6 +221,9 @@ static int if_usb_probe(struct usb_interface *intf,
udev->descriptor.bDeviceSubClass,
udev->descriptor.bDeviceProtocol);
+ init_usb_anchor(&cardp->rx_submitted);
+ init_usb_anchor(&cardp->tx_submitted);
+
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
if (usb_endpoint_is_bulk_in(endpoint)) {
@@ -426,7 +429,12 @@ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb
goto tx_ret;
}
- usb_kill_urb(cardp->tx_urb);
+ /* check if there are pending URBs */
+ if (!usb_anchor_empty(&cardp->tx_submitted)) {
+ lbs_deb_usbd(&cardp->udev->dev, "%s failed: pending URB\n", __func__);
+ ret = -EBUSY;
+ goto tx_ret;
+ }
usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
usb_sndbulkpipe(cardp->udev,
@@ -435,8 +443,10 @@ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb
cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET;
+ usb_anchor_urb(cardp->tx_urb, &cardp->tx_submitted);
if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) {
lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret);
+ usb_unanchor_urb(cardp->tx_urb);
} else {
lbs_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n");
ret = 0;
@@ -467,8 +477,10 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
cardp);
lbs_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
+ usb_anchor_urb(cardp->rx_urb, &cardp->rx_submitted);
if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) {
lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret);
+ usb_unanchor_urb(cardp->rx_urb);
kfree_skb(skb);
cardp->rx_skb = NULL;
ret = -1;
@@ -838,8 +850,8 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
}
/* Cancel any pending usb business */
- usb_kill_urb(cardp->rx_urb);
- usb_kill_urb(cardp->tx_urb);
+ usb_kill_anchored_urbs(&cardp->rx_submitted);
+ usb_kill_anchored_urbs(&cardp->tx_submitted);
cardp->fwlastblksent = 0;
cardp->fwdnldover = 0;
@@ -869,8 +881,8 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
if (cardp->bootcmdresp == BOOT_CMD_RESP_NOT_SUPPORTED) {
/* Return to normal operation */
ret = -EOPNOTSUPP;
- usb_kill_urb(cardp->rx_urb);
- usb_kill_urb(cardp->tx_urb);
+ usb_kill_anchored_urbs(&cardp->rx_submitted);
+ usb_kill_anchored_urbs(&cardp->tx_submitted);
if (if_usb_submit_rx_urb(cardp) < 0)
ret = -EIO;
goto done;
@@ -900,7 +912,7 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
wait_event_interruptible(cardp->fw_wq, cardp->surprise_removed || cardp->fwdnldover);
timer_delete_sync(&cardp->fw_timeout);
- usb_kill_urb(cardp->rx_urb);
+ usb_kill_anchored_urbs(&cardp->rx_submitted);
if (!cardp->fwdnldover) {
pr_info("failed to load fw, resetting device!\n");
@@ -960,8 +972,8 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
goto out;
/* Unlink tx & rx urb */
- usb_kill_urb(cardp->tx_urb);
- usb_kill_urb(cardp->rx_urb);
+ usb_kill_anchored_urbs(&cardp->tx_submitted);
+ usb_kill_anchored_urbs(&cardp->rx_submitted);
out:
return ret;
diff --git a/drivers/net/wireless/marvell/libertas/if_usb.h b/drivers/net/wireless/marvell/libertas/if_usb.h
index 7d0daeb33c3f..a0cd36197c2b 100644
--- a/drivers/net/wireless/marvell/libertas/if_usb.h
+++ b/drivers/net/wireless/marvell/libertas/if_usb.h
@@ -48,6 +48,9 @@ struct if_usb_card {
struct urb *rx_urb, *tx_urb;
struct lbs_private *priv;
+ struct usb_anchor rx_submitted;
+ struct usb_anchor tx_submitted;
+
struct sk_buff *rx_skb;
uint8_t ep_in;
diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c
index 34b4b34276d6..042b1fe5f0d6 100644
--- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c
+++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c
@@ -203,6 +203,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
spin_unlock_bh(&priv->wmm.ra_list_spinlock);
+ mwifiex_write_data_complete(adapter, skb_aggr, 1, -1);
return -1;
}
diff --git a/drivers/net/wireless/mediatek/mt76/channel.c b/drivers/net/wireless/mediatek/mt76/channel.c
index 2b705bdb7993..d9f8529db7ed 100644
--- a/drivers/net/wireless/mediatek/mt76/channel.c
+++ b/drivers/net/wireless/mediatek/mt76/channel.c
@@ -326,7 +326,7 @@ void mt76_roc_complete(struct mt76_phy *phy)
mlink->mvif->roc_phy = NULL;
if (phy->main_chandef.chan &&
!test_bit(MT76_MCU_RESET, &dev->phy.state))
- mt76_set_channel(phy, &phy->main_chandef, false);
+ __mt76_set_channel(phy, &phy->main_chandef, false);
mt76_put_vif_phy_link(phy, phy->roc_vif, phy->roc_link);
phy->roc_vif = NULL;
phy->roc_link = NULL;
@@ -370,6 +370,8 @@ int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (!phy)
return -EINVAL;
+ cancel_delayed_work_sync(&phy->mac_work);
+
mutex_lock(&dev->mutex);
if (phy->roc_vif || dev->scan.phy == phy ||
@@ -388,7 +390,14 @@ int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
phy->roc_vif = vif;
phy->roc_link = mlink;
cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20);
- mt76_set_channel(phy, &chandef, true);
+ ret = __mt76_set_channel(phy, &chandef, true);
+ if (ret) {
+ mlink->mvif->roc_phy = NULL;
+ phy->roc_vif = NULL;
+ phy->roc_link = NULL;
+ mt76_put_vif_phy_link(phy, vif, mlink);
+ goto out;
+ }
ieee80211_ready_on_channel(hw);
ieee80211_queue_delayed_work(phy->hw, &phy->roc_work,
msecs_to_jiffies(duration));
diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index f240016ed9f0..893ac14285ca 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -874,7 +874,12 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
if (!buf)
break;
- if (!mt76_queue_is_wed_rro(q))
+ if (mtk_wed_device_active(&dev->mmio.wed) &&
+ mt76_queue_is_wed_rro(q))
+ continue;
+
+ if (!mt76_queue_is_wed_rro_rxdmad_c(q) &&
+ !mt76_queue_is_wed_rro_ind(q))
mt76_put_page_pool_buf(buf, false);
} while (1);
@@ -1168,10 +1173,6 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
mt76_for_each_q_rx(dev, i) {
struct mt76_queue *q = &dev->q_rx[i];
- if (mtk_wed_device_active(&dev->mmio.wed) &&
- mt76_queue_is_wed_rro(q))
- continue;
-
netif_napi_del(&dev->napi[i]);
mt76_dma_rx_cleanup(dev, q);
diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c
index 573400d57ce7..afdb73661866 100644
--- a/drivers/net/wireless/mediatek/mt76/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/eeprom.c
@@ -9,6 +9,13 @@
#include <linux/nvmem-consumer.h>
#include <linux/etherdevice.h>
#include "mt76.h"
+#include "mt76_connac.h"
+
+enum mt76_sku_type {
+ MT76_SKU_RATE,
+ MT76_SKU_BACKOFF,
+ MT76_SKU_BACKOFF_BF_OFFSET,
+};
static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len)
{
@@ -292,7 +299,6 @@ mt76_find_channel_node(struct device_node *np, struct ieee80211_channel *chan)
}
EXPORT_SYMBOL_GPL(mt76_find_channel_node);
-
static s8
mt76_get_txs_delta(struct device_node *np, u8 nss)
{
@@ -306,9 +312,24 @@ mt76_get_txs_delta(struct device_node *np, u8 nss)
return be32_to_cpu(val[nss - 1]);
}
+static inline u8 mt76_backoff_n_chains(struct mt76_dev *dev, u8 idx)
+{
+ /* 0:1T1ss, 1:2T1ss, ..., 14:5T5ss */
+ static const u8 connac3_table[] = {
+ 1, 2, 3, 4, 5, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5};
+ static const u8 connac2_table[] = {
+ 1, 2, 3, 4, 2, 3, 4, 3, 4, 4, 0, 0, 0, 0, 0};
+
+ if (idx >= ARRAY_SIZE(connac3_table))
+ return 0;
+
+ return is_mt799x(dev) ? connac3_table[idx] : connac2_table[idx];
+}
+
static void
-mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const s8 *data,
- s8 target_power, s8 nss_delta, s8 *max_power)
+mt76_apply_array_limit(struct mt76_dev *dev, s8 *pwr, size_t pwr_len,
+ const s8 *data, s8 target_power, s8 nss_delta,
+ s8 *max_power, int n_chains, enum mt76_sku_type type)
{
int i;
@@ -316,18 +337,51 @@ mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const s8 *data,
return;
for (i = 0; i < pwr_len; i++) {
- pwr[i] = min_t(s8, target_power, data[i] + nss_delta);
+ u8 backoff_chain_idx = i;
+ int backoff_n_chains;
+ s8 backoff_delta;
+ s8 delta;
+
+ switch (type) {
+ case MT76_SKU_RATE:
+ delta = 0;
+ backoff_delta = 0;
+ backoff_n_chains = 0;
+ break;
+ case MT76_SKU_BACKOFF_BF_OFFSET:
+ backoff_chain_idx += 1;
+ fallthrough;
+ case MT76_SKU_BACKOFF:
+ delta = mt76_tx_power_path_delta(n_chains);
+ backoff_n_chains = mt76_backoff_n_chains(dev, backoff_chain_idx);
+ backoff_delta = mt76_tx_power_path_delta(backoff_n_chains);
+ break;
+ default:
+ return;
+ }
+
+ pwr[i] = min_t(s8, target_power + delta - backoff_delta, data[i] + nss_delta);
+
+ /* used for padding, doesn't need to be considered */
+ if (data[i] >= S8_MAX - 1)
+ continue;
+
+ /* only consider backoff value for the configured chain number */
+ if (type != MT76_SKU_RATE && n_chains != backoff_n_chains)
+ continue;
+
*max_power = max(*max_power, pwr[i]);
}
}
static void
-mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num,
- const s8 *data, size_t len, s8 target_power,
- s8 nss_delta)
+mt76_apply_multi_array_limit(struct mt76_dev *dev, s8 *pwr, size_t pwr_len,
+ s8 pwr_num, const s8 *data, size_t len,
+ s8 target_power, s8 nss_delta, s8 *max_power,
+ int n_chains, enum mt76_sku_type type)
{
+ static const int connac2_backoff_ru_idx = 2;
int i, cur;
- s8 max_power = -128;
if (!data)
return;
@@ -337,8 +391,26 @@ mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num,
if (len < pwr_len + 1)
break;
- mt76_apply_array_limit(pwr + pwr_len * i, pwr_len, data + 1,
- target_power, nss_delta, &max_power);
+ /* Each RU entry (RU26, RU52, RU106, BW20, ...) in the DTS
+ * corresponds to 10 stream combinations (1T1ss, 2T1ss, 3T1ss,
+ * 4T1ss, 2T2ss, 3T2ss, 4T2ss, 3T3ss, 4T3ss, 4T4ss).
+ *
+ * For beamforming tables:
+ * - In connac2, beamforming entries for BW20~BW160 and OFDM
+ * do not include 1T1ss.
+ * - In connac3, beamforming entries for BW20~BW160 and RU
+ * include 1T1ss, but OFDM beamforming does not include 1T1ss.
+ *
+ * Non-beamforming and RU entries for both connac2 and connac3
+ * include 1T1ss.
+ */
+ if (!is_mt799x(dev) && type == MT76_SKU_BACKOFF &&
+ i > connac2_backoff_ru_idx)
+ type = MT76_SKU_BACKOFF_BF_OFFSET;
+
+ mt76_apply_array_limit(dev, pwr + pwr_len * i, pwr_len, data + 1,
+ target_power, nss_delta, max_power,
+ n_chains, type);
if (--cur > 0)
continue;
@@ -360,18 +432,11 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
struct device_node *np;
const s8 *val;
char name[16];
- u32 mcs_rates = dev->drv->mcs_rates;
- u32 ru_rates = ARRAY_SIZE(dest->ru[0]);
char band;
size_t len;
- s8 max_power = 0;
- s8 max_power_backoff = -127;
+ s8 max_power = -127;
s8 txs_delta;
int n_chains = hweight16(phy->chainmask);
- s8 target_power_combine = target_power + mt76_tx_power_path_delta(n_chains);
-
- if (!mcs_rates)
- mcs_rates = 10;
memset(dest, target_power, sizeof(*dest) - sizeof(dest->path));
memset(&dest->path, 0, sizeof(dest->path));
@@ -409,46 +474,45 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
txs_delta = mt76_get_txs_delta(np, hweight16(phy->chainmask));
val = mt76_get_of_array_s8(np, "rates-cck", &len, ARRAY_SIZE(dest->cck));
- mt76_apply_array_limit(dest->cck, ARRAY_SIZE(dest->cck), val,
- target_power, txs_delta, &max_power);
+ mt76_apply_array_limit(dev, dest->cck, ARRAY_SIZE(dest->cck), val,
+ target_power, txs_delta, &max_power, n_chains, MT76_SKU_RATE);
- val = mt76_get_of_array_s8(np, "rates-ofdm",
- &len, ARRAY_SIZE(dest->ofdm));
- mt76_apply_array_limit(dest->ofdm, ARRAY_SIZE(dest->ofdm), val,
- target_power, txs_delta, &max_power);
+ val = mt76_get_of_array_s8(np, "rates-ofdm", &len, ARRAY_SIZE(dest->ofdm));
+ mt76_apply_array_limit(dev, dest->ofdm, ARRAY_SIZE(dest->ofdm), val,
+ target_power, txs_delta, &max_power, n_chains, MT76_SKU_RATE);
- val = mt76_get_of_array_s8(np, "rates-mcs", &len, mcs_rates + 1);
- mt76_apply_multi_array_limit(dest->mcs[0], ARRAY_SIZE(dest->mcs[0]),
- ARRAY_SIZE(dest->mcs), val, len,
- target_power, txs_delta);
+ val = mt76_get_of_array_s8(np, "rates-mcs", &len, ARRAY_SIZE(dest->mcs[0]) + 1);
+ mt76_apply_multi_array_limit(dev, dest->mcs[0], ARRAY_SIZE(dest->mcs[0]),
+ ARRAY_SIZE(dest->mcs), val, len, target_power,
+ txs_delta, &max_power, n_chains, MT76_SKU_RATE);
- val = mt76_get_of_array_s8(np, "rates-ru", &len, ru_rates + 1);
- mt76_apply_multi_array_limit(dest->ru[0], ARRAY_SIZE(dest->ru[0]),
- ARRAY_SIZE(dest->ru), val, len,
- target_power, txs_delta);
+ val = mt76_get_of_array_s8(np, "rates-ru", &len, ARRAY_SIZE(dest->ru[0]) + 1);
+ mt76_apply_multi_array_limit(dev, dest->ru[0], ARRAY_SIZE(dest->ru[0]),
+ ARRAY_SIZE(dest->ru), val, len, target_power,
+ txs_delta, &max_power, n_chains, MT76_SKU_RATE);
- max_power_backoff = max_power;
val = mt76_get_of_array_s8(np, "paths-cck", &len, ARRAY_SIZE(dest->path.cck));
- mt76_apply_array_limit(dest->path.cck, ARRAY_SIZE(dest->path.cck), val,
- target_power_combine, txs_delta, &max_power_backoff);
+ mt76_apply_array_limit(dev, dest->path.cck, ARRAY_SIZE(dest->path.cck), val,
+ target_power, txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF);
val = mt76_get_of_array_s8(np, "paths-ofdm", &len, ARRAY_SIZE(dest->path.ofdm));
- mt76_apply_array_limit(dest->path.ofdm, ARRAY_SIZE(dest->path.ofdm), val,
- target_power_combine, txs_delta, &max_power_backoff);
+ mt76_apply_array_limit(dev, dest->path.ofdm, ARRAY_SIZE(dest->path.ofdm), val,
+ target_power, txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF);
val = mt76_get_of_array_s8(np, "paths-ofdm-bf", &len, ARRAY_SIZE(dest->path.ofdm_bf));
- mt76_apply_array_limit(dest->path.ofdm_bf, ARRAY_SIZE(dest->path.ofdm_bf), val,
- target_power_combine, txs_delta, &max_power_backoff);
+ mt76_apply_array_limit(dev, dest->path.ofdm_bf, ARRAY_SIZE(dest->path.ofdm_bf), val,
+ target_power, txs_delta, &max_power, n_chains,
+ MT76_SKU_BACKOFF_BF_OFFSET);
val = mt76_get_of_array_s8(np, "paths-ru", &len, ARRAY_SIZE(dest->path.ru[0]) + 1);
- mt76_apply_multi_array_limit(dest->path.ru[0], ARRAY_SIZE(dest->path.ru[0]),
- ARRAY_SIZE(dest->path.ru), val, len,
- target_power_combine, txs_delta);
+ mt76_apply_multi_array_limit(dev, dest->path.ru[0], ARRAY_SIZE(dest->path.ru[0]),
+ ARRAY_SIZE(dest->path.ru), val, len, target_power,
+ txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF);
val = mt76_get_of_array_s8(np, "paths-ru-bf", &len, ARRAY_SIZE(dest->path.ru_bf[0]) + 1);
- mt76_apply_multi_array_limit(dest->path.ru_bf[0], ARRAY_SIZE(dest->path.ru_bf[0]),
- ARRAY_SIZE(dest->path.ru_bf), val, len,
- target_power_combine, txs_delta);
+ mt76_apply_multi_array_limit(dev, dest->path.ru_bf[0], ARRAY_SIZE(dest->path.ru_bf[0]),
+ ARRAY_SIZE(dest->path.ru_bf), val, len, target_power,
+ txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF);
return max_power;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index 75772979f438..4d041f88155c 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -726,6 +726,7 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
INIT_LIST_HEAD(&dev->rxwi_cache);
dev->token_size = dev->drv->token_size;
INIT_DELAYED_WORK(&dev->scan_work, mt76_scan_work);
+ spin_lock_init(&dev->scan_lock);
for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
skb_queue_head_init(&dev->rx_skb[i]);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index d05e83ea1cac..df93ab79c5b4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -540,7 +540,6 @@ struct mt76_driver_ops {
u32 survey_flags;
u16 txwi_size;
u16 token_size;
- u8 mcs_rates;
unsigned int link_data_size;
@@ -1002,6 +1001,7 @@ struct mt76_dev {
u32 rxfilter;
struct delayed_work scan_work;
+ spinlock_t scan_lock;
struct {
struct cfg80211_scan_request *req;
struct ieee80211_channel *chan;
@@ -1009,6 +1009,8 @@ struct mt76_dev {
struct mt76_vif_link *mlink;
struct mt76_phy *phy;
int chan_idx;
+ bool beacon_wait;
+ bool beacon_received;
} scan;
#ifdef CONFIG_NL80211_TESTMODE
@@ -1596,6 +1598,7 @@ int mt76_get_rate(struct mt76_dev *dev,
int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_scan_request *hw_req);
void mt76_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+void mt76_scan_rx_beacon(struct mt76_dev *dev, struct ieee80211_channel *chan);
void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
const u8 *mac);
void mt76_sw_scan_complete(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
index 45992fdcec60..ce0051468501 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
@@ -1167,21 +1167,6 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta,
}
EXPORT_SYMBOL_GPL(mt7615_mac_set_rates);
-void mt7615_mac_enable_rtscts(struct mt7615_dev *dev,
- struct ieee80211_vif *vif, bool enable)
-{
- struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
- u32 addr;
-
- addr = mt7615_mac_wtbl_addr(dev, mvif->sta.wcid.idx) + 3 * 4;
-
- if (enable)
- mt76_set(dev, addr, MT_WTBL_W3_RTS);
- else
- mt76_clear(dev, addr, MT_WTBL_W3_RTS);
-}
-EXPORT_SYMBOL_GPL(mt7615_mac_enable_rtscts);
-
static int
mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index 727266892c3d..fc619acbb40d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -583,9 +583,6 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
}
}
- if (changed & BSS_CHANGED_ERP_CTS_PROT)
- mt7615_mac_enable_rtscts(dev, vif, info->use_cts_prot);
-
if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) {
mt7615_mcu_add_bss_info(phy, vif, NULL, true);
mt7615_mcu_sta_add(phy, vif, NULL, true);
@@ -598,6 +595,10 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
BSS_CHANGED_BEACON_ENABLED))
mt7615_mcu_add_beacon(dev, hw, vif, info->enable_beacon);
+ if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT)
+ mt7615_mcu_set_protection(phy, vif, info->ht_operation_mode,
+ info->use_cts_prot);
+
if (changed & BSS_CHANGED_PS)
mt76_connac_mcu_set_vif_ps(&dev->mt76, vif);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index fc0054f8bd60..ff57ede87f71 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -2564,3 +2564,50 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_ROC),
&req, sizeof(req), false);
}
+
+int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif,
+ u8 ht_mode, bool use_cts_prot)
+{
+ struct mt7615_dev *dev = phy->dev;
+ struct {
+ u8 prot_idx;
+ u8 band;
+ u8 rsv[2];
+
+ bool long_nav;
+ bool prot_mm;
+ bool prot_gf;
+ bool prot_bw40;
+ bool prot_rifs;
+ bool prot_bw80;
+ bool prot_bw160;
+ u8 prot_erp_mask;
+ } __packed req = {
+ .prot_idx = 0x2,
+ .band = phy != &dev->phy,
+ };
+
+ switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) {
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
+ req.prot_mm = true;
+ req.prot_gf = true;
+ fallthrough;
+ case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
+ req.prot_bw40 = true;
+ break;
+ }
+
+ if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT)
+ req.prot_gf = true;
+
+ if (use_cts_prot) {
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ u8 i = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->mt76.omac_idx;
+
+ req.prot_erp_mask = BIT(i);
+ }
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(PROTECT_CTRL), &req,
+ sizeof(req), true);
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
index c93fd245c90f..391928405f32 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
@@ -467,8 +467,6 @@ void mt7615_mac_reset_counters(struct mt7615_phy *phy);
void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy);
void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable);
void mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy);
-void mt7615_mac_enable_rtscts(struct mt7615_dev *dev,
- struct ieee80211_vif *vif, bool enable);
void mt7615_mac_sta_poll(struct mt7615_dev *dev);
int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
@@ -523,7 +521,8 @@ int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable);
int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy);
int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy);
int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy);
-
+int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif,
+ u8 ht_mode, bool use_cts_prot);
int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_channel *chan, int duration);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
index eb3c24d51987..e4133e9181d0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
@@ -455,8 +455,6 @@ enum mt7615_reg_base {
#define MT_WTBL_RIUCR3_RATE6 GENMASK(19, 8)
#define MT_WTBL_RIUCR3_RATE7 GENMASK(31, 20)
-#define MT_WTBL_W3_RTS BIT(22)
-
#define MT_WTBL_W5_CHANGE_BW_RATE GENMASK(7, 5)
#define MT_WTBL_W5_SHORT_GI_20 BIT(8)
#define MT_WTBL_W5_SHORT_GI_40 BIT(9)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
index b41ca1410da9..aab463057009 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
@@ -1153,8 +1153,10 @@ void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
return;
wcid = (struct mt76_wcid *)sta->drv_priv;
- if (!test_and_set_bit(tid, &wcid->ampdu_state))
- ieee80211_start_tx_ba_session(sta, tid, 0);
+ if (!test_and_set_bit(tid, &wcid->ampdu_state)) {
+ if (ieee80211_start_tx_ba_session(sta, tid, 0))
+ clear_bit(tid, &wcid->ampdu_state);
+ }
}
EXPORT_SYMBOL_GPL(mt76_connac2_tx_check_aggr);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
index 0457712286d5..3f583e2a1dc1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -1295,8 +1295,10 @@ int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif_link *mvif,
wtbl_hdr);
ret = mt76_connac_mcu_sta_wed_update(dev, skb);
- if (ret)
+ if (ret) {
+ dev_kfree_skb(skb);
return ret;
+ }
ret = mt76_mcu_skb_send_msg(dev, skb, cmd, true);
if (ret)
@@ -1309,8 +1311,10 @@ int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif_link *mvif,
mt76_connac_mcu_sta_ba_tlv(skb, params, enable, tx);
ret = mt76_connac_mcu_sta_wed_update(dev, skb);
- if (ret)
+ if (ret) {
+ dev_kfree_skb(skb);
return ret;
+ }
return mt76_mcu_skb_send_msg(dev, skb, cmd, true);
}
@@ -2764,12 +2768,16 @@ int mt76_connac_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
return PTR_ERR(skb);
ret = mt76_connac_mcu_sta_key_tlv(sta_key_conf, skb, key, cmd);
- if (ret)
+ if (ret) {
+ dev_kfree_skb(skb);
return ret;
+ }
ret = mt76_connac_mcu_sta_wed_update(dev, skb);
- if (ret)
+ if (ret) {
+ dev_kfree_skb(skb);
return ret;
+ }
return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
index 22443cbc74ad..250c2d2479b0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
@@ -1294,6 +1294,7 @@ int mt7915_register_device(struct mt7915_dev *dev)
void mt7915_unregister_device(struct mt7915_dev *dev)
{
+ cancel_work_sync(&dev->dump_work);
mt7915_unregister_ext_phy(dev);
mt7915_coredump_unregister(dev);
mt7915_unregister_thermal(&dev->phy);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index cefe56c05731..cec2c4208255 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -232,19 +232,6 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
rcu_read_unlock();
}
-void mt7915_mac_enable_rtscts(struct mt7915_dev *dev,
- struct ieee80211_vif *vif, bool enable)
-{
- struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
- u32 addr;
-
- addr = mt7915_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5);
- if (enable)
- mt76_set(dev, addr, BIT(5));
- else
- mt76_clear(dev, addr, BIT(5));
-}
-
static void
mt7915_wed_check_ppe(struct mt7915_dev *dev, struct mt76_queue *q,
struct mt7915_sta *msta, struct sk_buff *skb,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index 90d5e79fbf74..0892291616ea 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -68,7 +68,7 @@ int mt7915_run(struct ieee80211_hw *hw)
if (ret)
goto out;
- ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b,
+ ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, MT7915_RTS_LEN_THRES,
phy->mt76->band_idx);
if (ret)
goto out;
@@ -633,8 +633,9 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
if (set_sta == 1)
mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE, false);
- if (changed & BSS_CHANGED_ERP_CTS_PROT)
- mt7915_mac_enable_rtscts(dev, vif, info->use_cts_prot);
+ if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT)
+ mt7915_mcu_set_protection(phy, vif, info->ht_operation_mode,
+ info->use_cts_prot);
if (changed & BSS_CHANGED_ERP_SLOT) {
int slottime = 9;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
index 00bff4d3aab8..023c92dac064 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
@@ -1765,8 +1765,10 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
}
out:
ret = mt76_connac_mcu_sta_wed_update(&dev->mt76, skb);
- if (ret)
+ if (ret) {
+ dev_kfree_skb(skb);
return ret;
+ }
return mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_EXT_CMD(STA_REC_UPDATE), true);
@@ -3954,6 +3956,68 @@ int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
return ret;
}
+int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif,
+ u8 ht_mode, bool use_cts_prot)
+{
+ struct mt7915_dev *dev = phy->dev;
+ int len = sizeof(struct sta_req_hdr) + sizeof(struct bss_info_prot);
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct bss_info_prot *prot;
+ struct sk_buff *skb;
+ struct tlv *tlv;
+ enum {
+ PROT_NONMEMBER = BIT(1),
+ PROT_20MHZ = BIT(2),
+ PROT_NONHT_MIXED = BIT(3),
+ PROT_LEGACY_ERP = BIT(5),
+ PROT_NONGF_STA = BIT(7),
+ };
+ u32 rts_threshold;
+
+ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
+ NULL, len);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_PROTECT_INFO,
+ sizeof(*prot));
+ prot = (struct bss_info_prot *)tlv;
+
+ switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) {
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
+ prot->prot_mode = cpu_to_le32(PROT_NONMEMBER);
+ break;
+ case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
+ prot->prot_mode = cpu_to_le32(PROT_20MHZ);
+ break;
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
+ prot->prot_mode = cpu_to_le32(PROT_NONHT_MIXED);
+ break;
+ }
+
+ if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT)
+ prot->prot_mode |= cpu_to_le32(PROT_NONGF_STA);
+
+ if (use_cts_prot)
+ prot->prot_mode |= cpu_to_le32(PROT_LEGACY_ERP);
+
+ /* reuse current RTS setting */
+ rts_threshold = phy->mt76->hw->wiphy->rts_threshold;
+ if (rts_threshold == (u32)-1)
+ prot->rts_len_thres = cpu_to_le32(MT7915_RTS_LEN_THRES);
+ else
+ prot->rts_len_thres = cpu_to_le32(rts_threshold);
+
+ prot->rts_pkt_thres = 0x2;
+
+ prot->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th);
+ if (!prot->he_rts_thres)
+ prot->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES);
+
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD(BSS_INFO_UPDATE), true);
+}
+
int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct cfg80211_he_bss_color *he_bss_color)
{
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
index 3af11a075a2f..22f73a5ed425 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
@@ -399,6 +399,17 @@ struct bss_info_inband_discovery {
__le16 prob_rsp_len;
} __packed __aligned(4);
+struct bss_info_prot {
+ __le16 tag;
+ __le16 len;
+ __le32 prot_type;
+ __le32 prot_mode;
+ __le32 rts_len_thres;
+ __le16 he_rts_thres;
+ u8 rts_pkt_thres;
+ u8 rsv[5];
+} __packed;
+
enum {
BSS_INFO_BCN_CSA,
BSS_INFO_BCN_BCC,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
index b5c06201b707..bf1d915a3ca2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
@@ -84,6 +84,8 @@
#define MT7915_CRIT_TEMP 110
#define MT7915_MAX_TEMP 120
+#define MT7915_RTS_LEN_THRES 0x92b
+
struct mt7915_vif;
struct mt7915_sta;
struct mt7915_dfs_pulse;
@@ -473,6 +475,8 @@ int mt7915_mcu_add_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *v
u32 changed);
int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
int enable, u32 changed);
+int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif,
+ u8 ht_mode, bool use_cts_prot);
int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_he_obss_pd *he_obss_pd);
int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 021335805acb..3d74fabe7408 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -371,12 +371,15 @@ void mt7921_roc_abort_sync(struct mt792x_dev *dev)
{
struct mt792x_phy *phy = &dev->phy;
+ if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
+ return;
+
timer_delete_sync(&phy->roc_timer);
- cancel_work_sync(&phy->roc_work);
- if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
- ieee80211_iterate_interfaces(mt76_hw(dev),
- IEEE80211_IFACE_ITER_RESUME_ALL,
- mt7921_roc_iter, (void *)phy);
+ cancel_work(&phy->roc_work);
+
+ ieee80211_iterate_interfaces(mt76_hw(dev),
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ mt7921_roc_iter, (void *)phy);
}
EXPORT_SYMBOL_GPL(mt7921_roc_abort_sync);
@@ -797,7 +800,8 @@ mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *vif, bool is_add)
}
out:
- mt7921_mcu_set_clc(dev, dev->mt76.alpha2, dev->country_ie_env);
+ if (vif->bss_conf.chanreq.oper.chan->band == NL80211_BAND_6GHZ)
+ mt7921_regd_update(dev);
}
int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
@@ -808,6 +812,9 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
int ret, idx;
+ if (sta->aid > MT7921_MAX_AID)
+ return -ENOENT;
+
idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1);
if (idx < 0)
return -ENOSPC;
@@ -851,6 +858,9 @@ int mt7921_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ if (sta->aid > MT7921_MAX_AID)
+ return -ENOENT;
+
if (ev != MT76_STA_EVENT_ASSOC)
return 0;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index 83fc7f49ff84..ad92af98e314 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -7,6 +7,8 @@
#include "../mt792x.h"
#include "regs.h"
+#define MT7921_MAX_AID 20
+
#define MT7921_TX_RING_SIZE 2048
#define MT7921_TX_MCU_RING_SIZE 256
#define MT7921_TX_FWDL_RING_SIZE 128
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c
index 3ce5d6fcc69d..c0c5cb9aff75 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c
@@ -91,6 +91,8 @@ int mt7925_mac_init(struct mt792x_dev *dev)
mt7925_mac_init_basic_rates(dev);
+ memzero_explicit(&dev->mt76.alpha2, sizeof(dev->mt76.alpha2));
+
return 0;
}
EXPORT_SYMBOL_GPL(mt7925_mac_init);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
index ebe872f58c88..82eedd80f694 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
@@ -804,8 +804,8 @@ mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
txwi[5] = cpu_to_le32(val);
val = MT_TXD6_DAS | FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
- if (!ieee80211_vif_is_mld(vif) ||
- (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0))
+ if (vif && (!ieee80211_vif_is_mld(vif) ||
+ (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0)))
val |= MT_TXD6_DIS_MAT;
txwi[6] = cpu_to_le32(val);
txwi[7] = 0;
@@ -846,11 +846,14 @@ static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb,
bool is_8023;
u16 fc, tid;
+ if (!sta)
+ return;
+
link_sta = rcu_dereference(sta->link[wcid->link_id]);
if (!link_sta)
return;
- if (!sta || !(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he))
+ if (!(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he))
return;
tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 2d358a96640c..fec54d5f4eaf 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -457,12 +457,16 @@ void mt7925_roc_abort_sync(struct mt792x_dev *dev)
{
struct mt792x_phy *phy = &dev->phy;
+ if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
+ return;
+
timer_delete_sync(&phy->roc_timer);
- cancel_work_sync(&phy->roc_work);
- if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
- ieee80211_iterate_interfaces(mt76_hw(dev),
- IEEE80211_IFACE_ITER_RESUME_ALL,
- mt7925_roc_iter, (void *)phy);
+
+ cancel_work(&phy->roc_work);
+
+ ieee80211_iterate_interfaces(mt76_hw(dev),
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ mt7925_roc_iter, (void *)phy);
}
EXPORT_SYMBOL_GPL(mt7925_roc_abort_sync);
@@ -541,7 +545,7 @@ static int mt7925_set_mlo_roc(struct mt792x_phy *phy,
phy->roc_grant = false;
- err = mt7925_mcu_set_mlo_roc(mconf, sel_links, 5, ++phy->roc_token_id);
+ err = mt7925_mcu_set_mlo_roc(phy, mconf, sel_links, 5, ++phy->roc_token_id);
if (err < 0) {
clear_bit(MT76_STATE_ROC, &phy->mt76->state);
goto out;
@@ -1894,10 +1898,8 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw,
struct mt792x_phy *phy = mt792x_hw_phy(hw);
struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct mt792x_bss_conf *mconf;
- struct ieee80211_bss_conf *link_conf;
mconf = mt792x_vif_to_link(mvif, info->link_id);
- link_conf = mt792x_vif_to_bss_conf(vif, mconf->link_id);
mt792x_mutex_acquire(dev);
@@ -1939,10 +1941,6 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw,
mvif->mlo_pm_state = MT792x_MLO_CHANGED_PS;
}
- if (changed & IEEE80211_CHANCTX_CHANGE_PUNCTURING)
- mt7925_mcu_set_eht_pp(mvif->phy->mt76, &mconf->mt76,
- link_conf, NULL);
-
if (changed & BSS_CHANGED_CQM)
mt7925_mcu_set_rssimonitor(dev, vif);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 47f91b9f1b95..abcdd0e0b3b5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1288,14 +1288,16 @@ int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
return PTR_ERR(skb);
ret = mt7925_mcu_sta_key_tlv(wcid, sta_key_conf, skb, key, cmd, msta);
- if (ret)
+ if (ret) {
+ dev_kfree_skb(skb);
return ret;
+ }
return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true);
}
-int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links,
- int duration, u8 token_id)
+int mt7925_mcu_set_mlo_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf,
+ u16 sel_links, int duration, u8 token_id)
{
struct mt792x_vif *mvif = mconf->vif;
struct ieee80211_vif *vif = container_of((void *)mvif,
@@ -1330,6 +1332,8 @@ int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links,
.roc[1].len = cpu_to_le16(sizeof(struct roc_acquire_tlv))
};
+ struct wiphy *wiphy = phy->mt76->hw->wiphy;
+
if (!mconf || hweight16(vif->valid_links) < 2 ||
hweight16(sel_links) != 2)
return -EPERM;
@@ -1352,7 +1356,8 @@ int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links,
is_AG_band |= links[i].chan->band == NL80211_BAND_2GHZ;
}
- if (vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP)
+ if (!(wiphy->iftype_ext_capab[0].mld_capa_and_ops &
+ IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS))
type = is_AG_band ? MT7925_ROC_REQ_MLSR_AG :
MT7925_ROC_REQ_MLSR_AA;
else
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
index 6b9bf1b89032..a1d902ccce6d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
@@ -349,8 +349,8 @@ int mt7925_set_tx_sar_pwr(struct ieee80211_hw *hw,
int mt7925_mcu_regval(struct mt792x_dev *dev, u32 regidx, u32 *val, bool set);
int mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
enum environment_cap env_cap);
-int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links,
- int duration, u8 token_id);
+int mt7925_mcu_set_mlo_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf,
+ u16 sel_links, int duration, u8 token_id);
int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf,
struct ieee80211_channel *chan, int duration,
enum mt7925_roc_req type, u8 token_id);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/regd.c b/drivers/net/wireless/mediatek/mt76/mt7925/regd.c
index 292087e882d1..16f56ee879d4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/regd.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/regd.c
@@ -232,7 +232,8 @@ int mt7925_regd_change(struct mt792x_phy *phy, char *alpha2)
dev->regd_user)
return -EINVAL;
- if (mdev->alpha2[0] != '0' && mdev->alpha2[1] != '0')
+ if ((mdev->alpha2[0] && mdev->alpha2[0] != '0') &&
+ (mdev->alpha2[1] && mdev->alpha2[1] != '0'))
return 0;
/* do not need to update the same country twice */
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
index 00a8286bd136..fca2d84493b9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
@@ -34,6 +34,20 @@ static const struct ieee80211_iface_combination if_comb_global = {
BIT(NL80211_CHAN_WIDTH_40) |
BIT(NL80211_CHAN_WIDTH_80) |
BIT(NL80211_CHAN_WIDTH_160),
+ .beacon_int_min_gcd = 100,
+};
+
+static const struct ieee80211_iface_combination if_comb_global_7992 = {
+ .limits = &if_limits_global,
+ .n_limits = 1,
+ .max_interfaces = 32,
+ .num_different_channels = MT7996_MAX_RADIOS - 1,
+ .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+ BIT(NL80211_CHAN_WIDTH_20) |
+ BIT(NL80211_CHAN_WIDTH_40) |
+ BIT(NL80211_CHAN_WIDTH_80) |
+ BIT(NL80211_CHAN_WIDTH_160),
+ .beacon_int_min_gcd = 100,
};
static const struct ieee80211_iface_limit if_limits[] = {
@@ -485,7 +499,8 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
hw->vif_data_size = sizeof(struct mt7996_vif);
hw->chanctx_data_size = sizeof(struct mt76_chanctx);
- wiphy->iface_combinations = &if_comb_global;
+ wiphy->iface_combinations = is_mt7996(&dev->mt76) ? &if_comb_global :
+ &if_comb_global_7992;
wiphy->n_iface_combinations = 1;
wiphy->radio = dev->radios;
@@ -521,6 +536,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD);
ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR);
ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
+ ieee80211_hw_set(hw, CHANCTX_STA_CSA);
hw->max_tx_fragments = 4;
@@ -842,8 +858,7 @@ void mt7996_rro_hw_init(struct mt7996_dev *dev)
}
} else {
/* set emul 3.0 function */
- mt76_wr(dev, MT_RRO_3_0_EMU_CONF,
- MT_RRO_3_0_EMU_CONF_EN_MASK);
+ mt76_set(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK);
mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE0,
dev->wed_rro.addr_elem[0].phy_addr);
@@ -1726,6 +1741,7 @@ int mt7996_register_device(struct mt7996_dev *dev)
void mt7996_unregister_device(struct mt7996_dev *dev)
{
+ cancel_work_sync(&dev->dump_work);
cancel_work_sync(&dev->wed_rro.work);
mt7996_unregister_phy(mt7996_phy3(dev));
mt7996_unregister_phy(mt7996_phy2(dev));
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index d4f3ee943b47..fc08ef94df63 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -527,7 +527,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
!(csum_status & (BIT(0) | BIT(2) | BIT(3))))
skb->ip_summed = CHECKSUM_UNNECESSARY;
- if (rxd1 & MT_RXD3_NORMAL_FCS_ERR)
+ if (rxd3 & MT_RXD3_NORMAL_FCS_ERR)
status->flag |= RX_FLAG_FAILED_FCS_CRC;
if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR)
@@ -554,6 +554,9 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
qos_ctl = FIELD_GET(MT_RXD10_QOS_CTL, v2);
seq_ctrl = FIELD_GET(MT_RXD10_SEQ_CTRL, v2);
+ if (ieee80211_is_beacon(fc))
+ mt76_scan_rx_beacon(&dev->mt76, mphy->chandef.chan);
+
rxd += 4;
if ((u8 *)rxd - skb->data >= skb->len)
return -EINVAL;
@@ -1139,10 +1142,10 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
* req
*/
if (le32_to_cpu(ptr[7]) & MT_TXD7_MAC_TXD) {
- u32 val;
+ u32 val, mac_txp_size = sizeof(struct mt76_connac_hw_txp);
ptr = (__le32 *)(txwi + MT_TXD_SIZE);
- memset((void *)ptr, 0, sizeof(struct mt76_connac_fw_txp));
+ memset((void *)ptr, 0, mac_txp_size);
val = FIELD_PREP(MT_TXP0_TOKEN_ID0, id) |
MT_TXP0_TOKEN_ID0_VALID_MASK;
@@ -1161,6 +1164,8 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
tx_info->buf[1].addr >> 32);
#endif
ptr[3] = cpu_to_le32(val);
+
+ tx_info->buf[0].len = MT_TXD_SIZE + mac_txp_size;
} else {
struct mt76_connac_txp_common *txp;
@@ -1270,8 +1275,9 @@ mt7996_tx_check_aggr(struct ieee80211_link_sta *link_sta,
if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
return;
- if (!test_and_set_bit(tid, &wcid->ampdu_state))
- ieee80211_start_tx_ba_session(link_sta->sta, tid, 0);
+ if (!test_and_set_bit(tid, &wcid->ampdu_state) &&
+ ieee80211_start_tx_ba_session(link_sta->sta, tid, 0))
+ clear_bit(tid, &wcid->ampdu_state);
}
static void
@@ -2397,6 +2403,7 @@ mt7996_mac_reset_sta_iter(void *data, struct ieee80211_sta *sta)
for (i = 0; i < ARRAY_SIZE(msta->link); i++) {
struct mt7996_sta_link *msta_link = NULL;
+ struct mt7996_phy *phy;
msta_link = rcu_replace_pointer(msta->link[i], msta_link,
lockdep_is_held(&dev->mt76.mutex));
@@ -2404,14 +2411,16 @@ mt7996_mac_reset_sta_iter(void *data, struct ieee80211_sta *sta)
continue;
mt7996_mac_sta_deinit_link(dev, msta_link);
+ phy = __mt7996_phy(dev, msta_link->wcid.phy_idx);
+ if (phy)
+ phy->mt76->num_sta--;
- if (msta->deflink_id == i) {
- msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
- continue;
- }
-
- kfree_rcu(msta_link, rcu_head);
+ if (msta_link != &msta->deflink)
+ kfree_rcu(msta_link, rcu_head);
}
+
+ msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
+ msta->seclink_id = msta->deflink_id;
}
static void
@@ -2544,6 +2553,7 @@ void mt7996_mac_reset_work(struct work_struct *work)
if (mtk_wed_device_active(&dev->mt76.mmio.wed))
mtk_wed_device_stop(&dev->mt76.mmio.wed);
+ mt7996_npu_hw_stop(dev);
ieee80211_stop_queues(mt76_hw(dev));
set_bit(MT76_RESET, &dev->mphy.state);
@@ -2570,8 +2580,6 @@ void mt7996_mac_reset_work(struct work_struct *work)
mutex_lock(&dev->mt76.mutex);
- mt7996_npu_hw_stop(dev);
-
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
@@ -2591,7 +2599,7 @@ void mt7996_mac_reset_work(struct work_struct *work)
mt7996_dma_start(dev, false, false);
if (!is_mt7996(&dev->mt76) && dev->mt76.hwrro_mode == MT76_HWRRO_V3)
- mt76_wr(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK);
+ mt76_set(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK);
if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
u32 wed_irq_mask = MT_INT_TX_DONE_BAND2 |
@@ -2974,7 +2982,7 @@ static void mt7996_dfs_stop_radar_detector(struct mt7996_phy *phy)
static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int rdd_idx)
{
- int err, region;
+ int region;
switch (dev->mt76.region) {
case NL80211_DFS_ETSI:
@@ -2989,11 +2997,7 @@ static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int rdd_idx)
break;
}
- err = mt7996_mcu_rdd_cmd(dev, RDD_START, rdd_idx, region);
- if (err < 0)
- return err;
-
- return mt7996_mcu_rdd_cmd(dev, RDD_DET_MODE, rdd_idx, 1);
+ return mt7996_mcu_rdd_cmd(dev, RDD_START, rdd_idx, region);
}
static int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index f16135f0b7f9..ff3050c2344a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -79,6 +79,7 @@ static void mt7996_stop_phy(struct mt7996_phy *phy)
mutex_lock(&dev->mt76.mutex);
+ mt7996_mcu_rdd_resume_tx(phy);
mt7996_mcu_set_radio_en(phy, false);
clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
@@ -300,7 +301,6 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
.cmd = SET_KEY,
.link_id = link_conf->link_id,
};
- struct mt76_txq *mtxq;
int mld_idx, idx, ret;
mlink->idx = __ffs64(~dev->mt76.vif_mask);
@@ -343,11 +343,6 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
mt7996_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
- if (vif->txq) {
- mtxq = (struct mt76_txq *)vif->txq->drv_priv;
- mtxq->wcid = idx;
- }
-
if (vif->type != NL80211_IFTYPE_AP &&
(!mlink->omac_idx || mlink->omac_idx > 3))
vif->offload_flags = 0;
@@ -370,9 +365,13 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it);
- if (!mlink->wcid->offchannel &&
- mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED)
+ if (vif->txq && !mlink->wcid->offchannel &&
+ mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED) {
+ struct mt76_txq *mtxq = (struct mt76_txq *)vif->txq->drv_priv;
+
mvif->mt76.deflink_id = link_conf->link_id;
+ mtxq->wcid = idx;
+ }
return 0;
}
@@ -403,17 +402,28 @@ void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif,
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
- if (!mlink->wcid->offchannel &&
+ if (vif->txq && !mlink->wcid->offchannel &&
mvif->mt76.deflink_id == link_conf->link_id) {
struct ieee80211_bss_conf *iter;
+ struct mt76_txq *mtxq;
unsigned int link_id;
mvif->mt76.deflink_id = IEEE80211_LINK_UNSPECIFIED;
+ mtxq = (struct mt76_txq *)vif->txq->drv_priv;
+ /* Primary link will be removed, look for a new one */
for_each_vif_active_link(vif, iter, link_id) {
- if (link_id != IEEE80211_LINK_UNSPECIFIED) {
- mvif->mt76.deflink_id = link_id;
- break;
- }
+ struct mt7996_vif_link *link;
+
+ if (link_id == link_conf->link_id)
+ continue;
+
+ link = mt7996_vif_link(dev, vif, link_id);
+ if (!link)
+ continue;
+
+ mtxq->wcid = link->msta_link.wcid.idx;
+ mvif->mt76.deflink_id = link_id;
+ break;
}
}
@@ -933,6 +943,40 @@ mt7996_channel_switch_beacon(struct ieee80211_hw *hw,
mutex_unlock(&dev->mt76.mutex);
}
+static int
+mt7996_post_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *link_conf)
+{
+ struct cfg80211_chan_def *chandef = &link_conf->chanreq.oper;
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_band_phy(dev, chandef->chan->band);
+ int ret;
+
+ mutex_lock(&dev->mt76.mutex);
+
+ ret = mt7996_mcu_rdd_resume_tx(phy);
+
+ mutex_unlock(&dev->mt76.mutex);
+
+ return ret;
+}
+
+static void
+mt7996_sta_init_txq_wcid(struct ieee80211_sta *sta, int idx)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
+ struct mt76_txq *mtxq;
+
+ if (!sta->txq[i])
+ continue;
+
+ mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
+ mtxq->wcid = idx;
+ }
+}
+
static int
mt7996_mac_sta_init_link(struct mt7996_dev *dev,
struct ieee80211_bss_conf *link_conf,
@@ -950,21 +994,10 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev,
return -ENOSPC;
if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) {
- int i;
-
msta_link = &msta->deflink;
msta->deflink_id = link_id;
msta->seclink_id = msta->deflink_id;
-
- for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
- struct mt76_txq *mtxq;
-
- if (!sta->txq[i])
- continue;
-
- mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
- mtxq->wcid = idx;
- }
+ mt7996_sta_init_txq_wcid(sta, idx);
} else {
msta_link = kzalloc_obj(*msta_link);
if (!msta_link)
@@ -1010,6 +1043,7 @@ void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev,
list_del_init(&msta_link->rc_list);
spin_unlock_bh(&dev->mt76.sta_poll_lock);
+ rcu_assign_pointer(dev->mt76.wcid[msta_link->wcid.idx], NULL);
mt76_wcid_cleanup(&dev->mt76, &msta_link->wcid);
mt76_wcid_mask_clear(dev->mt76.wcid_mask, msta_link->wcid.idx);
}
@@ -1024,8 +1058,7 @@ mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
struct mt7996_sta_link *msta_link = NULL;
- struct mt7996_vif_link *link;
- struct mt76_phy *mphy;
+ struct mt7996_phy *phy;
msta_link = rcu_replace_pointer(msta->link[link_id], msta_link,
lockdep_is_held(&mdev->mutex));
@@ -1034,25 +1067,36 @@ mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
mt7996_mac_wtbl_update(dev, msta_link->wcid.idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
-
mt7996_mac_sta_deinit_link(dev, msta_link);
- link = mt7996_vif_link(dev, vif, link_id);
- if (!link)
- continue;
- mphy = mt76_vif_link_phy(&link->mt76);
- if (!mphy)
- continue;
+ phy = __mt7996_phy(dev, msta_link->wcid.phy_idx);
+ if (phy)
+ phy->mt76->num_sta--;
- mphy->num_sta--;
if (msta->deflink_id == link_id) {
msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
- continue;
+ if (msta->seclink_id == link_id) {
+ /* no secondary link available */
+ msta->seclink_id = msta->deflink_id;
+ } else {
+ struct mt7996_sta_link *msta_seclink;
+
+ /* switch to the secondary link */
+ msta_seclink = mt76_dereference(
+ msta->link[msta->seclink_id],
+ mdev);
+ if (msta_seclink) {
+ msta->deflink_id = msta->seclink_id;
+ mt7996_sta_init_txq_wcid(sta,
+ msta_seclink->wcid.idx);
+ }
+ }
} else if (msta->seclink_id == link_id) {
- msta->seclink_id = IEEE80211_LINK_UNSPECIFIED;
+ msta->seclink_id = msta->deflink_id;
}
- kfree_rcu(msta_link, rcu_head);
+ if (msta_link != &msta->deflink)
+ kfree_rcu(msta_link, rcu_head);
}
}
@@ -2306,6 +2350,7 @@ const struct ieee80211_ops mt7996_ops = {
.release_buffered_frames = mt76_release_buffered_frames,
.get_txpower = mt7996_get_txpower,
.channel_switch_beacon = mt7996_channel_switch_beacon,
+ .post_channel_switch = mt7996_post_channel_switch,
.get_stats = mt7996_get_stats,
.get_et_sset_count = mt7996_get_et_sset_count,
.get_et_stats = mt7996_get_et_stats,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index c0c042de477b..20ade7ae7da9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -233,7 +233,7 @@ mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd,
event = (struct mt7996_mcu_uni_event *)skb->data;
ret = le32_to_cpu(event->status);
/* skip invalid event */
- if (mcu_cmd != event->cid)
+ if (mcu_cmd != le16_to_cpu(event->cid))
ret = -EAGAIN;
} else {
skb_pull(skb, sizeof(struct mt7996_mcu_rxd));
@@ -416,24 +416,32 @@ mt7996_mcu_rx_radar_detected(struct mt7996_dev *dev, struct sk_buff *skb)
break;
case MT_RDD_IDX_BACKGROUND:
if (!dev->rdd2_phy)
- return;
+ goto err;
mphy = dev->rdd2_phy->mt76;
break;
default:
- dev_err(dev->mt76.dev, "Unknown RDD idx %d\n", r->rdd_idx);
- return;
+ goto err;
}
if (!mphy)
- return;
+ goto err;
- if (r->rdd_idx == MT_RDD_IDX_BACKGROUND)
+ if (r->rdd_idx == MT_RDD_IDX_BACKGROUND) {
cfg80211_background_radar_event(mphy->hw->wiphy,
&dev->rdd2_chandef,
GFP_ATOMIC);
- else
+ } else {
+ struct mt7996_phy *phy = mphy->priv;
+
+ phy->rdd_tx_paused = true;
ieee80211_radar_detected(mphy->hw, NULL);
+ }
dev->hw_pattern++;
+
+ return;
+
+err:
+ dev_err(dev->mt76.dev, "Invalid RDD idx %d\n", r->rdd_idx);
}
static void
@@ -4557,6 +4565,35 @@ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable)
&req, sizeof(req), true);
}
+int mt7996_mcu_rdd_resume_tx(struct mt7996_phy *phy)
+{
+ struct {
+ u8 band_idx;
+ u8 _rsv[3];
+
+ __le16 tag;
+ __le16 len;
+ u8 mac_enable;
+ u8 _rsv2[3];
+ } __packed req = {
+ .band_idx = phy->mt76->band_idx,
+ .tag = cpu_to_le16(UNI_BAND_CONFIG_MAC_ENABLE_CTRL),
+ .len = cpu_to_le16(sizeof(req) - 4),
+ .mac_enable = 2,
+ };
+ int ret;
+
+ if (!phy->rdd_tx_paused)
+ return 0;
+
+ ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(BAND_CONFIG),
+ &req, sizeof(req), true);
+ if (!ret)
+ phy->rdd_tx_paused = false;
+
+ return ret;
+}
+
int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val)
{
struct {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
index e0b83ac9f5e2..f87a8d316f17 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
@@ -25,8 +25,8 @@ struct mt7996_mcu_rxd {
};
struct mt7996_mcu_uni_event {
- u8 cid;
- u8 __rsv[3];
+ __le16 cid;
+ u8 __rsv[2];
__le32 status; /* 0: success, others: fail */
} __packed;
@@ -837,6 +837,7 @@ enum {
enum {
UNI_BAND_CONFIG_RADIO_ENABLE,
UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08,
+ UNI_BAND_CONFIG_MAC_ENABLE_CTRL = 0x0c,
};
enum {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index 7a884311800e..d31864f973cc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -377,6 +377,7 @@ struct mt7996_phy {
bool has_aux_rx;
bool counter_reset;
+ bool rdd_tx_paused;
};
struct mt7996_dev {
@@ -726,6 +727,7 @@ int mt7996_mcu_get_temperature(struct mt7996_phy *phy);
int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state);
int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable);
int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy);
+int mt7996_mcu_rdd_resume_tx(struct mt7996_phy *phy);
int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val);
int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy,
struct cfg80211_chan_def *chandef);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/npu.c b/drivers/net/wireless/mediatek/mt76/mt7996/npu.c
index 29bb735da4cb..067ef647e404 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/npu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/npu.c
@@ -320,33 +320,38 @@ int mt7996_npu_hw_init(struct mt7996_dev *dev)
int mt7996_npu_hw_stop(struct mt7996_dev *dev)
{
struct airoha_npu *npu;
- int i, err;
+ int i, err = 0;
u32 info;
+ mutex_lock(&dev->mt76.mutex);
+
npu = rcu_dereference_protected(dev->mt76.mmio.npu, &dev->mt76.mutex);
if (!npu)
- return 0;
+ goto unlock;
err = mt76_npu_send_msg(npu, 4, WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR,
0, GFP_KERNEL);
if (err)
- return err;
+ goto unlock;
for (i = 0; i < 10; i++) {
err = mt76_npu_get_msg(npu, 3, WLAN_FUNC_GET_WAIT_NPU_INFO,
&info, GFP_KERNEL);
- if (err)
- continue;
+ if (!err && !info)
+ break;
- if (info) {
- err = -ETIMEDOUT;
- continue;
- }
+ err = -ETIMEDOUT;
+ usleep_range(10000, 15000);
}
if (!err)
err = mt76_npu_send_msg(npu, 6,
WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR,
0, GFP_KERNEL);
+ else
+ dev_err(dev->mt76.dev, "npu stop failed\n");
+unlock:
+ mutex_unlock(&dev->mt76.mutex);
+
return err;
}
diff --git a/drivers/net/wireless/mediatek/mt76/npu.c b/drivers/net/wireless/mediatek/mt76/npu.c
index ec36975f6dc9..9679237f7398 100644
--- a/drivers/net/wireless/mediatek/mt76/npu.c
+++ b/drivers/net/wireless/mediatek/mt76/npu.c
@@ -457,6 +457,7 @@ int mt76_npu_init(struct mt76_dev *dev, phys_addr_t phy_addr, int type)
dev->mmio.npu_type = type;
/* NPU offloading requires HW-RRO for RX packet reordering. */
dev->hwrro_mode = MT76_HWRRO_V3_1;
+ dev->rx_token_size = 32768;
rcu_assign_pointer(dev->mmio.npu, npu);
rcu_assign_pointer(dev->mmio.ppe_dev, ppe_dev);
diff --git a/drivers/net/wireless/mediatek/mt76/scan.c b/drivers/net/wireless/mediatek/mt76/scan.c
index 63b0447e55c1..ab153b4df047 100644
--- a/drivers/net/wireless/mediatek/mt76/scan.c
+++ b/drivers/net/wireless/mediatek/mt76/scan.c
@@ -16,7 +16,7 @@ static void mt76_scan_complete(struct mt76_dev *dev, bool abort)
clear_bit(MT76_SCANNING, &phy->state);
- if (dev->scan.chan && phy->main_chandef.chan &&
+ if (dev->scan.chan && phy->main_chandef.chan && phy->offchannel &&
!test_bit(MT76_MCU_RESET, &dev->phy.state))
mt76_set_channel(phy, &phy->main_chandef, false);
mt76_put_vif_phy_link(phy, dev->scan.vif, dev->scan.mlink);
@@ -27,6 +27,10 @@ static void mt76_scan_complete(struct mt76_dev *dev, bool abort)
void mt76_abort_scan(struct mt76_dev *dev)
{
+ spin_lock_bh(&dev->scan_lock);
+ dev->scan.beacon_wait = false;
+ spin_unlock_bh(&dev->scan_lock);
+
cancel_delayed_work_sync(&dev->scan_work);
mt76_scan_complete(dev, true);
}
@@ -77,6 +81,28 @@ mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid)
rcu_read_unlock();
}
+void mt76_scan_rx_beacon(struct mt76_dev *dev, struct ieee80211_channel *chan)
+{
+ struct mt76_phy *phy;
+
+ spin_lock(&dev->scan_lock);
+
+ if (!dev->scan.beacon_wait || dev->scan.beacon_received ||
+ dev->scan.chan != chan)
+ goto out;
+
+ phy = dev->scan.phy;
+ if (!phy)
+ goto out;
+
+ dev->scan.beacon_received = true;
+ ieee80211_queue_delayed_work(phy->hw, &dev->scan_work, 0);
+
+out:
+ spin_unlock(&dev->scan_lock);
+}
+EXPORT_SYMBOL_GPL(mt76_scan_rx_beacon);
+
void mt76_scan_work(struct work_struct *work)
{
struct mt76_dev *dev = container_of(work, struct mt76_dev,
@@ -85,14 +111,26 @@ void mt76_scan_work(struct work_struct *work)
struct cfg80211_chan_def chandef = {};
struct mt76_phy *phy = dev->scan.phy;
int duration = HZ / 9; /* ~110 ms */
+ bool beacon_rx, offchannel = true;
int i;
+ if (!phy || !req)
+ return;
+
+ spin_lock_bh(&dev->scan_lock);
+ beacon_rx = dev->scan.beacon_wait && dev->scan.beacon_received;
+ dev->scan.beacon_wait = false;
+ spin_unlock_bh(&dev->scan_lock);
+
+ if (beacon_rx)
+ goto probe;
+
if (dev->scan.chan_idx >= req->n_channels) {
mt76_scan_complete(dev, false);
return;
}
- if (dev->scan.chan && phy->num_sta) {
+ if (dev->scan.chan && phy->num_sta && phy->offchannel) {
dev->scan.chan = NULL;
mt76_set_channel(phy, &phy->main_chandef, false);
goto out;
@@ -100,20 +138,34 @@ void mt76_scan_work(struct work_struct *work)
dev->scan.chan = req->channels[dev->scan.chan_idx++];
cfg80211_chandef_create(&chandef, dev->scan.chan, NL80211_CHAN_HT20);
- mt76_set_channel(phy, &chandef, true);
+ if (phy->main_chandef.chan == dev->scan.chan) {
+ chandef = phy->main_chandef;
+ offchannel = false;
+ }
+
+ mt76_set_channel(phy, &chandef, offchannel);
- if (!req->n_ssids ||
- chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR))
+ if (!req->n_ssids)
goto out;
- duration = HZ / 16; /* ~60 ms */
+ if (chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) {
+ spin_lock_bh(&dev->scan_lock);
+ dev->scan.beacon_received = false;
+ dev->scan.beacon_wait = true;
+ spin_unlock_bh(&dev->scan_lock);
+ goto out;
+ }
+
+probe:
+ if (phy->offchannel)
+ duration = HZ / 16; /* ~60 ms */
local_bh_disable();
for (i = 0; i < req->n_ssids; i++)
mt76_scan_send_probe(dev, &req->ssids[i]);
local_bh_enable();
out:
- if (dev->scan.chan)
+ if (dev->scan.chan && phy->offchannel)
duration = max_t(int, duration,
msecs_to_jiffies(req->duration +
(req->duration >> 5)));
diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c
index d080469264cf..f0010336e78c 100644
--- a/drivers/net/wireless/realtek/rtlwifi/pci.c
+++ b/drivers/net/wireless/realtek/rtlwifi/pci.c
@@ -1674,6 +1674,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw)
synchronize_irq(rtlpci->pdev->irq);
tasklet_kill(&rtlpriv->works.irq_tasklet);
+ tasklet_kill(&rtlpriv->works.irq_prepare_bcn_tasklet);
cancel_work_sync(&rtlpriv->works.lps_change_work);
}
diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
index ee6ab2136b9a..ee8a36003e5d 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -4860,7 +4860,7 @@ static void rtw89_phy_cfo_set_crystal_cap(struct rtw89_dev *rtwdev,
{
struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking;
const struct rtw89_chip_info *chip = rtwdev->chip;
- u8 sc_xi_val, sc_xo_val;
+ u8 sc_xi_val = 0, sc_xo_val = 0;
if (!force && cfo->crystal_cap == crystal_cap)
return;
diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c
index d17c701c7888..08c27bb438b5 100644
--- a/drivers/nfc/trf7970a.c
+++ b/drivers/nfc/trf7970a.c
@@ -317,6 +317,7 @@
#define TRF7970A_RSSI_OSC_STATUS_RSSI_MASK (BIT(2) | BIT(1) | BIT(0))
#define TRF7970A_RSSI_OSC_STATUS_RSSI_X_MASK (BIT(5) | BIT(4) | BIT(3))
#define TRF7970A_RSSI_OSC_STATUS_RSSI_OSC_OK BIT(6)
+#define TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL 1
#define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0)
#define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL BIT(1)
@@ -1300,7 +1301,7 @@ static int trf7970a_is_rf_field(struct trf7970a *trf, bool *is_rf_field)
if (ret)
return ret;
- if (rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK)
+ if ((rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) > TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL)
*is_rf_field = true;
else
*is_rf_field = false;
diff --git a/drivers/nvme/host/apple.c b/drivers/nvme/host/apple.c
index 423c9c628e7b..c692fc73babf 100644
--- a/drivers/nvme/host/apple.c
+++ b/drivers/nvme/host/apple.c
@@ -1009,6 +1009,7 @@ static void apple_nvme_init_queue(struct apple_nvme_queue *q)
unsigned int depth = apple_nvme_queue_depth(q);
struct apple_nvme *anv = queue_to_apple_nvme(q);
+ q->sq_tail = 0;
q->cq_head = 0;
q->cq_phase = 1;
if (anv->hw->has_lsq_nvmmu)
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index db5fc9bf6627..4c052ed18cb8 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -2241,6 +2241,7 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid, bool polled)
static const struct blk_mq_ops nvme_mq_admin_ops = {
.queue_rq = nvme_queue_rq,
.complete = nvme_pci_complete_rq,
+ .commit_rqs = nvme_commit_rqs,
.init_hctx = nvme_admin_init_hctx,
.init_request = nvme_pci_init_request,
.timeout = nvme_timeout,
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index 255ebd948dfe..dc65894696ad 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -351,7 +351,7 @@ static void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd)
static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue);
-static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd)
+static int nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd)
{
struct bio_vec *iov = cmd->iov;
struct scatterlist *sg;
@@ -364,22 +364,19 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd)
offset = cmd->rbytes_done;
cmd->sg_idx = offset / PAGE_SIZE;
sg_offset = offset % PAGE_SIZE;
- if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) {
- nvmet_tcp_fatal_error(cmd->queue);
- return;
- }
+ if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt)
+ return -EPROTO;
+
sg = &cmd->req.sg[cmd->sg_idx];
sg_remaining = cmd->req.sg_cnt - cmd->sg_idx;
while (length) {
- if (!sg_remaining) {
- nvmet_tcp_fatal_error(cmd->queue);
- return;
- }
- if (!sg->length || sg->length <= sg_offset) {
- nvmet_tcp_fatal_error(cmd->queue);
- return;
- }
+ if (!sg_remaining)
+ return -EPROTO;
+
+ if (!sg->length || sg->length <= sg_offset)
+ return -EPROTO;
+
u32 iov_len = min_t(u32, length, sg->length - sg_offset);
bvec_set_page(iov, sg_page(sg), iov_len,
@@ -394,6 +391,7 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd)
iov_iter_bvec(&cmd->recv_msg.msg_iter, ITER_DEST, cmd->iov,
nr_pages, cmd->pdu_len);
+ return 0;
}
static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue)
@@ -957,7 +955,7 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue)
return 0;
}
-static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue,
+static int nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue,
struct nvmet_tcp_cmd *cmd, struct nvmet_req *req)
{
size_t data_len = le32_to_cpu(req->cmd->common.dptr.sgl.length);
@@ -973,19 +971,23 @@ static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue,
if (!nvme_is_write(cmd->req.cmd) || !data_len ||
data_len > cmd->req.port->inline_data_size) {
nvmet_prepare_receive_pdu(queue);
- return;
+ return 0;
}
ret = nvmet_tcp_map_data(cmd);
if (unlikely(ret)) {
pr_err("queue %d: failed to map data\n", queue->idx);
nvmet_tcp_fatal_error(queue);
- return;
+ return -EPROTO;
}
queue->rcv_state = NVMET_TCP_RECV_DATA;
- nvmet_tcp_build_pdu_iovec(cmd);
cmd->flags |= NVMET_TCP_F_INIT_FAILED;
+ ret = nvmet_tcp_build_pdu_iovec(cmd);
+ if (unlikely(ret))
+ pr_err("queue %d: failed to build PDU iovec\n", queue->idx);
+
+ return ret;
}
static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue)
@@ -1037,7 +1039,10 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue)
goto err_proto;
}
cmd->pdu_recv = 0;
- nvmet_tcp_build_pdu_iovec(cmd);
+ if (unlikely(nvmet_tcp_build_pdu_iovec(cmd))) {
+ pr_err("queue %d: failed to build PDU iovec\n", queue->idx);
+ goto err_proto;
+ }
queue->cmd = cmd;
queue->rcv_state = NVMET_TCP_RECV_DATA;
@@ -1100,8 +1105,7 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue)
le32_to_cpu(req->cmd->common.dptr.sgl.length),
le16_to_cpu(req->cqe->status));
- nvmet_tcp_handle_req_failure(queue, queue->cmd, req);
- return 0;
+ return nvmet_tcp_handle_req_failure(queue, queue->cmd, req);
}
ret = nvmet_tcp_map_data(queue->cmd);
@@ -1118,8 +1122,11 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue)
if (nvmet_tcp_need_data_in(queue->cmd)) {
if (nvmet_tcp_has_inline_data(queue->cmd)) {
queue->rcv_state = NVMET_TCP_RECV_DATA;
- nvmet_tcp_build_pdu_iovec(queue->cmd);
- return 0;
+ ret = nvmet_tcp_build_pdu_iovec(queue->cmd);
+ if (unlikely(ret))
+ pr_err("queue %d: failed to build PDU iovec\n",
+ queue->idx);
+ return ret;
}
/* send back R2T */
nvmet_tcp_queue_response(&queue->cmd->req);
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index 866641666e41..da3f5eba4341 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -2742,8 +2742,8 @@ struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table,
break;
}
}
- break;
}
+ break;
}
if (IS_ERR(dest_opp)) {
diff --git a/drivers/opp/debugfs.c b/drivers/opp/debugfs.c
index 8fc6238b1728..61506d30d5ff 100644
--- a/drivers/opp/debugfs.c
+++ b/drivers/opp/debugfs.c
@@ -130,22 +130,24 @@ void opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
{
struct dentry *pdentry = opp_table->dentry;
struct dentry *d;
- unsigned long id;
- char name[25]; /* 20 chars for 64 bit value + 5 (opp:\0) */
+ char name[36]; /* "opp:"(4) + u64(20) + "-" (1) + u32(10) + NULL(1) */
/*
* Get directory name for OPP.
*
- * - Normally rate is unique to each OPP, use it to get unique opp-name.
+ * - Normally rate is unique to each OPP, use it to get unique opp-name,
+ * together with performance level if available.
* - For some devices rate isn't available or there are multiple, use
* index instead for them.
*/
- if (likely(opp_table->clk_count == 1 && opp->rates[0]))
- id = opp->rates[0];
- else
- id = _get_opp_count(opp_table);
-
- snprintf(name, sizeof(name), "opp:%lu", id);
+ if (likely(opp_table->clk_count == 1 && opp->rates[0])) {
+ if (opp->level == OPP_LEVEL_UNSET)
+ snprintf(name, sizeof(name), "opp:%lu", opp->rates[0]);
+ else
+ snprintf(name, sizeof(name), "opp:%lu-%u", opp->rates[0], opp->level);
+ } else {
+ snprintf(name, sizeof(name), "opp:%u", _get_opp_count(opp_table));
+ }
/* Create per-opp directory */
d = debugfs_create_dir(name, pdentry);
diff --git a/drivers/pci/controller/cadence/pci-sky1.c b/drivers/pci/controller/cadence/pci-sky1.c
index d8c216dc120d..9853a9c82c0e 100644
--- a/drivers/pci/controller/cadence/pci-sky1.c
+++ b/drivers/pci/controller/cadence/pci-sky1.c
@@ -176,8 +176,10 @@ static int sky1_pcie_probe(struct platform_device *pdev)
cdns_pcie->is_rc = 1;
reg_off = devm_kzalloc(dev, sizeof(*reg_off), GFP_KERNEL);
- if (!reg_off)
+ if (!reg_off) {
+ pci_ecam_free(pcie->cfg);
return -ENOMEM;
+ }
reg_off->ip_reg_bank_offset = SKY1_IP_REG_BANK;
reg_off->ip_cfg_ctrl_reg_offset = SKY1_IP_CFG_CTRL_REG_BANK;
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index db3154c1eccb..0bc9e6e90e0e 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -147,6 +147,13 @@ static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0);
cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
+ value = cdns_pcie_rp_readl(pcie, CDNS_PCIE_RP_CAP_OFFSET + PCI_EXP_LNKCAP);
+ if (rc->quirk_broken_aspm_l0s)
+ value &= ~PCI_EXP_LNKCAP_ASPM_L0S;
+ if (rc->quirk_broken_aspm_l1)
+ value &= ~PCI_EXP_LNKCAP_ASPM_L1;
+ cdns_pcie_rp_writel(pcie, CDNS_PCIE_RP_CAP_OFFSET + PCI_EXP_LNKCAP, value);
+
return 0;
}
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index 277f3706a4f4..574e9cf4d003 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -115,6 +115,8 @@ struct cdns_pcie {
* @quirk_detect_quiet_flag: LTSSM Detect Quiet min delay set as quirk
* @ecam_supported: Whether the ECAM is supported
* @no_inbound_map: Whether inbound mapping is supported
+ * @quirk_broken_aspm_l0s: Disable ASPM L0s support as quirk
+ * @quirk_broken_aspm_l1: Disable ASPM L1 support as quirk
*/
struct cdns_pcie_rc {
struct cdns_pcie pcie;
@@ -127,6 +129,8 @@ struct cdns_pcie_rc {
unsigned int quirk_detect_quiet_flag:1;
unsigned int ecam_supported:1;
unsigned int no_inbound_map:1;
+ unsigned int quirk_broken_aspm_l0s:1;
+ unsigned int quirk_broken_aspm_l1:1;
};
/**
@@ -338,6 +342,21 @@ static inline u16 cdns_pcie_rp_readw(struct cdns_pcie *pcie, u32 reg)
return cdns_pcie_read_sz(addr, 0x2);
}
+static inline void cdns_pcie_rp_writel(struct cdns_pcie *pcie,
+ u32 reg, u32 value)
+{
+ void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg;
+
+ cdns_pcie_write_sz(addr, 0x4, value);
+}
+
+static inline u32 cdns_pcie_rp_readl(struct cdns_pcie *pcie, u32 reg)
+{
+ void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg;
+
+ return cdns_pcie_read_sz(addr, 0x4);
+}
+
static inline void cdns_pcie_hpa_rp_writeb(struct cdns_pcie *pcie,
u32 reg, u8 value)
{
diff --git a/drivers/pci/controller/cadence/pcie-sg2042.c b/drivers/pci/controller/cadence/pcie-sg2042.c
index 0c50c74d03ee..4a2af4d0713e 100644
--- a/drivers/pci/controller/cadence/pcie-sg2042.c
+++ b/drivers/pci/controller/cadence/pcie-sg2042.c
@@ -48,6 +48,8 @@ static int sg2042_pcie_probe(struct platform_device *pdev)
bridge->child_ops = &sg2042_pcie_child_ops;
rc = pci_host_bridge_priv(bridge);
+ rc->quirk_broken_aspm_l0s = 1;
+ rc->quirk_broken_aspm_l1 = 1;
pcie = &rc->pcie;
pcie->dev = dev;
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index e01a225cf3ab..0a494c9dd6aa 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -117,6 +117,8 @@ enum imx_pcie_variants {
#define IMX_PCIE_FLAG_HAS_LUT BIT(10)
#define IMX_PCIE_FLAG_8GT_ECN_ERR051586 BIT(11)
#define IMX_PCIE_FLAG_SKIP_L23_READY BIT(12)
+/* Preserve MSI capability for platforms that require it */
+#define IMX_PCIE_FLAG_KEEP_MSI_CAP BIT(13)
#define imx_check_flag(pci, val) (pci->drvdata->flags & val)
@@ -1647,7 +1649,6 @@ static int imx_pcie_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct dw_pcie *pci;
struct imx_pcie *imx_pcie;
- struct device_node *np;
struct device_node *node = dev->of_node;
int i, ret, domain;
u16 val;
@@ -1674,7 +1675,8 @@ static int imx_pcie_probe(struct platform_device *pdev)
pci->pp.ops = &imx_pcie_host_dw_pme_ops;
/* Find the PHY if one is defined, only imx7d uses it */
- np = of_parse_phandle(node, "fsl,imx7d-pcie-phy", 0);
+ struct device_node *np __free(device_node) =
+ of_parse_phandle(node, "fsl,imx7d-pcie-phy", 0);
if (np) {
struct resource res;
@@ -1830,6 +1832,8 @@ static int imx_pcie_probe(struct platform_device *pdev)
} else {
if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_SKIP_L23_READY))
pci->pp.skip_l23_ready = true;
+ if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_KEEP_MSI_CAP))
+ pci->pp.keep_rp_msi_en = true;
pci->pp.use_atu_msg = true;
ret = dw_pcie_host_init(&pci->pp);
if (ret < 0)
@@ -1908,6 +1912,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
[IMX7D] = {
.variant = IMX7D,
.flags = IMX_PCIE_FLAG_SUPPORTS_SUSPEND |
+ IMX_PCIE_FLAG_KEEP_MSI_CAP |
IMX_PCIE_FLAG_HAS_APP_RESET |
IMX_PCIE_FLAG_SKIP_L23_READY |
IMX_PCIE_FLAG_HAS_PHY_RESET,
@@ -1920,6 +1925,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
[IMX8MQ] = {
.variant = IMX8MQ,
.flags = IMX_PCIE_FLAG_HAS_APP_RESET |
+ IMX_PCIE_FLAG_KEEP_MSI_CAP |
IMX_PCIE_FLAG_HAS_PHY_RESET |
IMX_PCIE_FLAG_SUPPORTS_SUSPEND,
.gpr = "fsl,imx8mq-iomuxc-gpr",
@@ -1934,6 +1940,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
[IMX8MM] = {
.variant = IMX8MM,
.flags = IMX_PCIE_FLAG_SUPPORTS_SUSPEND |
+ IMX_PCIE_FLAG_KEEP_MSI_CAP |
IMX_PCIE_FLAG_HAS_PHYDRV |
IMX_PCIE_FLAG_HAS_APP_RESET,
.gpr = "fsl,imx8mm-iomuxc-gpr",
diff --git a/drivers/pci/controller/dwc/pcie-designware-debugfs.c b/drivers/pci/controller/dwc/pcie-designware-debugfs.c
index 0d1340c9b364..9461be074490 100644
--- a/drivers/pci/controller/dwc/pcie-designware-debugfs.c
+++ b/drivers/pci/controller/dwc/pcie-designware-debugfs.c
@@ -208,10 +208,11 @@ static ssize_t lane_detect_write(struct file *file, const char __user *buf,
struct dw_pcie *pci = file->private_data;
struct dwc_pcie_rasdes_info *rinfo = pci->debugfs->rasdes_info;
u32 lane, val;
+ int ret;
- val = kstrtou32_from_user(buf, count, 0, &lane);
- if (val)
- return val;
+ ret = kstrtou32_from_user(buf, count, 0, &lane);
+ if (ret)
+ return ret;
val = dw_pcie_readl_dbi(pci, rinfo->ras_cap_offset + SD_STATUS_L1LANE_REG);
val &= ~(LANE_SELECT);
@@ -347,10 +348,11 @@ static ssize_t counter_enable_write(struct file *file, const char __user *buf,
struct dw_pcie *pci = pdata->pci;
struct dwc_pcie_rasdes_info *rinfo = pci->debugfs->rasdes_info;
u32 val, enable;
+ int ret;
- val = kstrtou32_from_user(buf, count, 0, &enable);
- if (val)
- return val;
+ ret = kstrtou32_from_user(buf, count, 0, &enable);
+ if (ret)
+ return ret;
mutex_lock(&rinfo->reg_event_lock);
set_event_number(pdata, pci, rinfo);
@@ -408,10 +410,11 @@ static ssize_t counter_lane_write(struct file *file, const char __user *buf,
struct dw_pcie *pci = pdata->pci;
struct dwc_pcie_rasdes_info *rinfo = pci->debugfs->rasdes_info;
u32 val, lane;
+ int ret;
- val = kstrtou32_from_user(buf, count, 0, &lane);
- if (val)
- return val;
+ ret = kstrtou32_from_user(buf, count, 0, &lane);
+ if (ret)
+ return ret;
mutex_lock(&rinfo->reg_event_lock);
set_event_number(pdata, pci, rinfo);
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index c57ae4d6c5c0..ab2e7de5c55e 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -754,7 +754,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
val = dw_pcie_ep_readw_dbi(ep, func_no, reg);
val &= ~PCI_MSIX_FLAGS_QSIZE;
val |= nr_irqs - 1; /* encoded as N-1 */
- dw_pcie_writew_dbi(pci, reg, val);
+ dw_pcie_ep_writew_dbi(ep, func_no, reg, val);
reg = ep_func->msix_cap + PCI_MSIX_TABLE;
val = offset | bir;
@@ -1110,7 +1110,8 @@ static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci)
{
struct dw_pcie_ep *ep = &pci->ep;
u8 funcs = ep->epc->max_functions;
- u8 func_no;
+ u32 func0_lnkcap, lnkcap;
+ u8 func_no, offset;
dw_pcie_dbi_ro_wr_en(pci);
@@ -1118,6 +1119,32 @@ static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci)
dw_pcie_ep_init_rebar_registers(ep, func_no);
dw_pcie_setup(pci);
+
+ /*
+ * PCIe r7.0, section 7.5.3.6 states that for multi-function
+ * endpoints, max link width and speed fields must report same
+ * values for all functions. However, dw_pcie_setup() programs
+ * these fields only for function 0. Hence, mirror these fields
+ * to all other functions as well.
+ */
+ if (funcs > 1) {
+ offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ func0_lnkcap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
+ func0_lnkcap = FIELD_GET(PCI_EXP_LNKCAP_MLW |
+ PCI_EXP_LNKCAP_SLS, func0_lnkcap);
+
+ for (func_no = 1; func_no < funcs; func_no++) {
+ offset = dw_pcie_ep_find_capability(ep, func_no,
+ PCI_CAP_ID_EXP);
+ lnkcap = dw_pcie_ep_readl_dbi(ep, func_no,
+ offset + PCI_EXP_LNKCAP);
+ FIELD_MODIFY(PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS,
+ &lnkcap, func0_lnkcap);
+ dw_pcie_ep_writel_dbi(ep, func_no,
+ offset + PCI_EXP_LNKCAP, lnkcap);
+ }
+ }
+
dw_pcie_dbi_ro_wr_dis(pci);
}
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 6ae6189e9b8a..6adde3fc32be 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -1171,7 +1171,7 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
* the MSI and MSI-X capabilities of the Root Port to allow the drivers
* to fall back to INTx instead.
*/
- if (pp->use_imsi_rx) {
+ if (pp->use_imsi_rx && !pp->keep_rp_msi_en) {
dw_pcie_remove_capability(pci, PCI_CAP_ID_MSI);
dw_pcie_remove_capability(pci, PCI_CAP_ID_MSIX);
}
@@ -1300,15 +1300,24 @@ int dw_pcie_resume_noirq(struct dw_pcie *pci)
ret = dw_pcie_start_link(pci);
if (ret)
- return ret;
+ goto err_deinit;
ret = dw_pcie_wait_for_link(pci);
- if (ret)
- return ret;
+ if (ret == -ETIMEDOUT)
+ goto err_stop_link;
if (pci->pp.ops->post_init)
pci->pp.ops->post_init(&pci->pp);
+ return 0;
+
+err_stop_link:
+ dw_pcie_stop_link(pci);
+
+err_deinit:
+ if (pci->pp.ops->deinit)
+ pci->pp.ops->deinit(&pci->pp);
+
return ret;
}
EXPORT_SYMBOL_GPL(dw_pcie_resume_noirq);
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 5741c09dde7f..bb4e82fbfd5c 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -487,13 +487,13 @@ static inline void dw_pcie_writel_atu_ob(struct dw_pcie *pci, u32 index, u32 reg
static inline u32 dw_pcie_enable_ecrc(u32 val)
{
/*
- * DesignWare core version 4.90A has a design issue where the 'TD'
- * bit in the Control register-1 of the ATU outbound region acts
- * like an override for the ECRC setting, i.e., the presence of TLP
- * Digest (ECRC) in the outgoing TLPs is solely determined by this
- * bit. This is contrary to the PCIe spec which says that the
- * enablement of the ECRC is solely determined by the AER
- * registers.
+ * DWC versions 0x3530302a and 0x3536322a have a design issue where
+ * the 'TD' bit in the Control register-1 of the ATU outbound
+ * region acts like an override for the ECRC setting, i.e., the
+ * presence of TLP Digest (ECRC) in the outgoing TLPs is solely
+ * determined by this bit. This is contrary to the PCIe spec which
+ * says that the enablement of the ECRC is solely determined by the
+ * AER registers.
*
* Because of this, even when the ECRC is enabled through AER
* registers, the transactions going through ATU won't have TLP
@@ -563,7 +563,7 @@ int dw_pcie_prog_outbound_atu(struct dw_pcie *pci,
if (upper_32_bits(limit_addr) > upper_32_bits(parent_bus_addr) &&
dw_pcie_ver_is_ge(pci, 460A))
val |= PCIE_ATU_INCREASE_REGION_SIZE;
- if (dw_pcie_ver_is(pci, 490A))
+ if (dw_pcie_ver_is(pci, 490A) || dw_pcie_ver_is(pci, 500A))
val = dw_pcie_enable_ecrc(val);
dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_REGION_CTRL1, val);
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index ae6389dd9caa..3e69ef60165b 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -34,8 +34,10 @@
#define DW_PCIE_VER_470A 0x3437302a
#define DW_PCIE_VER_480A 0x3438302a
#define DW_PCIE_VER_490A 0x3439302a
+#define DW_PCIE_VER_500A 0x3530302a
#define DW_PCIE_VER_520A 0x3532302a
#define DW_PCIE_VER_540A 0x3534302a
+#define DW_PCIE_VER_562A 0x3536322a
#define __dw_pcie_ver_cmp(_pci, _ver, _op) \
((_pci)->version _op DW_PCIE_VER_ ## _ver)
@@ -421,6 +423,7 @@ struct dw_pcie_host_ops {
struct dw_pcie_rp {
bool use_imsi_rx:1;
+ bool keep_rp_msi_en:1;
bool cfg0_io_shared:1;
u64 cfg0_base;
void __iomem *va_cfg0_base;
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index 67a16af69ddc..9fdfc88ac151 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -350,15 +350,20 @@ static void qcom_pcie_clear_aspm_l0s(struct dw_pcie *pci)
dw_pcie_dbi_ro_wr_dis(pci);
}
-static void qcom_pcie_clear_hpc(struct dw_pcie *pci)
+static void qcom_pcie_set_slot_nccs(struct dw_pcie *pci)
{
u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
u32 val;
dw_pcie_dbi_ro_wr_en(pci);
+ /*
+ * Qcom PCIe Root Ports do not support generating command completion
+ * notifications for the Hot-Plug commands. So set the NCCS field to
+ * avoid waiting for the completions.
+ */
val = readl(pci->dbi_base + offset + PCI_EXP_SLTCAP);
- val &= ~PCI_EXP_SLTCAP_HPC;
+ val |= PCI_EXP_SLTCAP_NCCS;
writel(val, pci->dbi_base + offset + PCI_EXP_SLTCAP);
dw_pcie_dbi_ro_wr_dis(pci);
@@ -558,7 +563,7 @@ static int qcom_pcie_post_init_2_1_0(struct qcom_pcie *pcie)
writel(CFG_BRIDGE_SB_INIT,
pci->dbi_base + AXI_MSTR_RESP_COMP_CTRL1);
- qcom_pcie_clear_hpc(pcie->pci);
+ qcom_pcie_set_slot_nccs(pcie->pci);
return 0;
}
@@ -638,7 +643,7 @@ static int qcom_pcie_post_init_1_0_0(struct qcom_pcie *pcie)
writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT);
}
- qcom_pcie_clear_hpc(pcie->pci);
+ qcom_pcie_set_slot_nccs(pcie->pci);
return 0;
}
@@ -731,7 +736,7 @@ static int qcom_pcie_post_init_2_3_2(struct qcom_pcie *pcie)
val |= EN;
writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
- qcom_pcie_clear_hpc(pcie->pci);
+ qcom_pcie_set_slot_nccs(pcie->pci);
return 0;
}
@@ -1037,7 +1042,7 @@ static int qcom_pcie_post_init_2_7_0(struct qcom_pcie *pcie)
writel(WR_NO_SNOOP_OVERRIDE_EN | RD_NO_SNOOP_OVERRIDE_EN,
pcie->parf + PARF_NO_SNOOP_OVERRIDE);
- qcom_pcie_clear_hpc(pcie->pci);
+ qcom_pcie_set_slot_nccs(pcie->pci);
return 0;
}
diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
index a6912e85e4dd..8c7bc0691e52 100644
--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
+++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
@@ -426,7 +426,7 @@ static const struct pci_epc_features rcar_gen4_pcie_epc_features = {
.bar[BAR_3] = { .type = BAR_RESERVED, },
.bar[BAR_4] = { .type = BAR_FIXED, .fixed_size = 256 },
.bar[BAR_5] = { .type = BAR_RESERVED, },
- .align = SZ_1M,
+ .align = SZ_4K,
};
static const struct pci_epc_features*
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index 06571d806ab3..336d3c759547 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -35,8 +35,8 @@
#include <soc/tegra/bpmp-abi.h>
#include "../../pci.h"
-#define TEGRA194_DWC_IP_VER 0x490A
-#define TEGRA234_DWC_IP_VER 0x562A
+#define TEGRA194_DWC_IP_VER DW_PCIE_VER_500A
+#define TEGRA234_DWC_IP_VER DW_PCIE_VER_562A
#define APPL_PINMUX 0x0
#define APPL_PINMUX_PEX_RST BIT(0)
@@ -137,7 +137,11 @@
#define APPL_DEBUG_PM_LINKST_IN_L0 0x11
#define APPL_DEBUG_LTSSM_STATE_MASK GENMASK(8, 3)
#define APPL_DEBUG_LTSSM_STATE_SHIFT 3
-#define LTSSM_STATE_PRE_DETECT 5
+#define LTSSM_STATE_DETECT_QUIET 0x00
+#define LTSSM_STATE_DETECT_ACT 0x08
+#define LTSSM_STATE_PRE_DETECT_QUIET 0x28
+#define LTSSM_STATE_DETECT_WAIT 0x30
+#define LTSSM_STATE_L2_IDLE 0xa8
#define APPL_RADM_STATUS 0xE4
#define APPL_PM_XMT_TURNOFF_STATE BIT(0)
@@ -198,9 +202,8 @@
#define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK GENMASK(11, 8)
#define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT 8
-#define PME_ACK_TIMEOUT 10000
-
-#define LTSSM_TIMEOUT 50000 /* 50ms */
+#define LTSSM_DELAY_US 10000 /* 10 ms */
+#define LTSSM_TIMEOUT_US 120000 /* 120 ms */
#define GEN3_GEN4_EQ_PRESET_INIT 5
@@ -231,6 +234,7 @@ struct tegra_pcie_dw_of_data {
bool has_sbr_reset_fix;
bool has_l1ss_exit_fix;
bool has_ltr_req_fix;
+ bool disable_l1_2;
u32 cdm_chk_int_en_bit;
u32 gen4_preset_vec;
u8 n_fts[2];
@@ -482,15 +486,6 @@ static irqreturn_t tegra_pcie_ep_irq_thread(int irq, void *arg)
if (val & PCI_COMMAND_MASTER) {
ktime_t timeout;
- /* 110us for both snoop and no-snoop */
- val = FIELD_PREP(PCI_LTR_VALUE_MASK, 110) |
- FIELD_PREP(PCI_LTR_SCALE_MASK, 2) |
- LTR_MSG_REQ |
- FIELD_PREP(PCI_LTR_NOSNOOP_VALUE, 110) |
- FIELD_PREP(PCI_LTR_NOSNOOP_SCALE, 2) |
- LTR_NOSNOOP_MSG_REQ;
- appl_writel(pcie, val, APPL_LTR_MSG_1);
-
/* Send LTR upstream */
val = appl_readl(pcie, APPL_LTR_MSG_2);
val |= APPL_LTR_MSG_2_LTR_MSG_REQ_STATE;
@@ -685,6 +680,23 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie)
if (pcie->supports_clkreq)
pci->l1ss_support = true;
+ /*
+ * Disable L1.2 capability advertisement for Tegra234 Endpoint mode.
+ * Tegra234 has a hardware bug where during L1.2 exit, the UPHY PLL is
+ * powered up immediately without waiting for REFCLK to stabilize. This
+ * causes the PLL to fail to lock to the correct frequency, resulting in
+ * PCIe link loss. Since there is no hardware fix available, we prevent
+ * the Endpoint from advertising L1.2 support by clearing the L1.2 bits
+ * in the L1 PM Substates Capabilities register. This ensures the host
+ * will not attempt to enter L1.2 state with this Endpoint.
+ */
+ if (pcie->of_data->disable_l1_2 &&
+ pcie->of_data->mode == DW_PCIE_EP_TYPE) {
+ val = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
+ val &= ~(PCI_L1SS_CAP_PCIPM_L1_2 | PCI_L1SS_CAP_ASPM_L1_2);
+ dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, val);
+ }
+
/* Program L0s and L1 entrance latencies */
val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
val &= ~PORT_AFR_L0S_ENTRANCE_LAT_MASK;
@@ -1022,7 +1034,8 @@ static void tegra_pcie_dw_stop_link(struct dw_pcie *pci)
{
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
- disable_irq(pcie->pex_rst_irq);
+ if (pcie->of_data->mode == DW_PCIE_EP_TYPE)
+ disable_irq(pcie->pex_rst_irq);
}
static const struct dw_pcie_ops tegra_dw_pcie_ops = {
@@ -1163,9 +1176,9 @@ static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie)
return err;
}
- pcie->pex_refclk_sel_gpiod = devm_gpiod_get(pcie->dev,
- "nvidia,refclk-select",
- GPIOD_OUT_HIGH);
+ pcie->pex_refclk_sel_gpiod = devm_gpiod_get_optional(pcie->dev,
+ "nvidia,refclk-select",
+ GPIOD_OUT_HIGH);
if (IS_ERR(pcie->pex_refclk_sel_gpiod)) {
int err = PTR_ERR(pcie->pex_refclk_sel_gpiod);
const char *level = KERN_ERR;
@@ -1255,44 +1268,6 @@ static int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie,
return 0;
}
-static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie)
-{
- struct dw_pcie_rp *pp = &pcie->pci.pp;
- struct pci_bus *child, *root_port_bus = NULL;
- struct pci_dev *pdev;
-
- /*
- * link doesn't go into L2 state with some of the endpoints with Tegra
- * if they are not in D0 state. So, need to make sure that immediate
- * downstream devices are in D0 state before sending PME_TurnOff to put
- * link into L2 state.
- * This is as per PCI Express Base r4.0 v1.0 September 27-2017,
- * 5.2 Link State Power Management (Page #428).
- */
-
- list_for_each_entry(child, &pp->bridge->bus->children, node) {
- if (child->parent == pp->bridge->bus) {
- root_port_bus = child;
- break;
- }
- }
-
- if (!root_port_bus) {
- dev_err(pcie->dev, "Failed to find downstream bus of Root Port\n");
- return;
- }
-
- /* Bring downstream devices to D0 if they are not already in */
- list_for_each_entry(pdev, &root_port_bus->devices, bus_list) {
- if (PCI_SLOT(pdev->devfn) == 0) {
- if (pci_set_power_state(pdev, PCI_D0))
- dev_err(pcie->dev,
- "Failed to transition %s to D0 state\n",
- dev_name(&pdev->dev));
- }
- }
-}
-
static int tegra_pcie_get_slot_regulators(struct tegra_pcie_dw *pcie)
{
pcie->slot_ctl_3v3 = devm_regulator_get_optional(pcie->dev, "vpcie3v3");
@@ -1553,9 +1528,10 @@ static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie)
val |= APPL_PM_XMT_TURNOFF_STATE;
appl_writel(pcie, val, APPL_RADM_STATUS);
- return readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, val,
- val & APPL_DEBUG_PM_LINKST_IN_L2_LAT,
- 1, PME_ACK_TIMEOUT);
+ return readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val,
+ val & APPL_DEBUG_PM_LINKST_IN_L2_LAT,
+ PCIE_PME_TO_L2_TIMEOUT_US/10,
+ PCIE_PME_TO_L2_TIMEOUT_US);
}
static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
@@ -1590,23 +1566,22 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
data &= ~APPL_PINMUX_PEX_RST;
appl_writel(pcie, data, APPL_PINMUX);
+ err = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, data,
+ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) ||
+ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) ||
+ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) ||
+ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT),
+ LTSSM_DELAY_US, LTSSM_TIMEOUT_US);
+ if (err)
+ dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", data, err);
+
/*
- * Some cards do not go to detect state even after de-asserting
- * PERST#. So, de-assert LTSSM to bring link to detect state.
+ * Deassert LTSSM state to stop the state toggling between
+ * Polling and Detect.
*/
data = readl(pcie->appl_base + APPL_CTRL);
data &= ~APPL_CTRL_LTSSM_EN;
writel(data, pcie->appl_base + APPL_CTRL);
-
- err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG,
- data,
- ((data &
- APPL_DEBUG_LTSSM_STATE_MASK) >>
- APPL_DEBUG_LTSSM_STATE_SHIFT) ==
- LTSSM_STATE_PRE_DETECT,
- 1, LTSSM_TIMEOUT);
- if (err)
- dev_info(pcie->dev, "Link didn't go to detect state\n");
}
/*
* DBI registers may not be accessible after this as PLL-E would be
@@ -1622,7 +1597,6 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
{
- tegra_pcie_downstream_dev_to_D0(pcie);
dw_pcie_host_deinit(&pcie->pci.pp);
tegra_pcie_dw_pme_turnoff(pcie);
tegra_pcie_unconfig_controller(pcie);
@@ -1680,19 +1654,24 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie)
if (pcie->ep_state == EP_STATE_DISABLED)
return;
- /* Disable LTSSM */
+ ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val,
+ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) ||
+ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) ||
+ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) ||
+ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT) ||
+ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_L2_IDLE),
+ LTSSM_DELAY_US, LTSSM_TIMEOUT_US);
+ if (ret)
+ dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", val, ret);
+
+ /*
+ * Deassert LTSSM state to stop the state toggling between
+ * Polling and Detect.
+ */
val = appl_readl(pcie, APPL_CTRL);
val &= ~APPL_CTRL_LTSSM_EN;
appl_writel(pcie, val, APPL_CTRL);
- ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val,
- ((val & APPL_DEBUG_LTSSM_STATE_MASK) >>
- APPL_DEBUG_LTSSM_STATE_SHIFT) ==
- LTSSM_STATE_PRE_DETECT,
- 1, LTSSM_TIMEOUT);
- if (ret)
- dev_err(pcie->dev, "Failed to go Detect state: %d\n", ret);
-
reset_control_assert(pcie->core_rst);
tegra_pcie_disable_phy(pcie);
@@ -1771,10 +1750,6 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
goto fail_phy;
}
- /* Perform cleanup that requires refclk */
- pci_epc_deinit_notify(pcie->pci.ep.epc);
- dw_pcie_ep_cleanup(&pcie->pci.ep);
-
/* Clear any stale interrupt statuses */
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L0);
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_0_0);
@@ -1833,8 +1808,25 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
val |= APPL_INTR_EN_L1_0_0_RDLH_LINK_UP_INT_EN;
appl_writel(pcie, val, APPL_INTR_EN_L1_0_0);
+ /* 110us for both snoop and no-snoop */
+ val = FIELD_PREP(PCI_LTR_VALUE_MASK, 110) |
+ FIELD_PREP(PCI_LTR_SCALE_MASK, 2) |
+ LTR_MSG_REQ |
+ FIELD_PREP(PCI_LTR_NOSNOOP_VALUE, 110) |
+ FIELD_PREP(PCI_LTR_NOSNOOP_SCALE, 2) |
+ LTR_NOSNOOP_MSG_REQ;
+ appl_writel(pcie, val, APPL_LTR_MSG_1);
+
reset_control_deassert(pcie->core_rst);
+ /* Perform cleanup that requires refclk and core reset deasserted */
+ pci_epc_deinit_notify(pcie->pci.ep.epc);
+ dw_pcie_ep_cleanup(&pcie->pci.ep);
+
+ val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
+ val &= ~PORT_LOGIC_SPEED_CHANGE;
+ dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
+
if (pcie->update_fc_fixup) {
val = dw_pcie_readl_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF);
val |= 0x1 << CFG_TIMER_CTRL_ACK_NAK_SHIFT;
@@ -2277,6 +2269,7 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
static void tegra_pcie_dw_remove(struct platform_device *pdev)
{
struct tegra_pcie_dw *pcie = platform_get_drvdata(pdev);
+ struct dw_pcie_ep *ep = &pcie->pci.ep;
if (pcie->of_data->mode == DW_PCIE_RC_TYPE) {
if (!pcie->link_state)
@@ -2288,6 +2281,7 @@ static void tegra_pcie_dw_remove(struct platform_device *pdev)
} else {
disable_irq(pcie->pex_rst_irq);
pex_ep_event_pex_rst_assert(pcie);
+ dw_pcie_ep_deinit(ep);
}
pm_runtime_disable(pcie->dev);
@@ -2296,16 +2290,28 @@ static void tegra_pcie_dw_remove(struct platform_device *pdev)
gpiod_set_value(pcie->pex_refclk_sel_gpiod, 0);
}
-static int tegra_pcie_dw_suspend_late(struct device *dev)
+static int tegra_pcie_dw_suspend(struct device *dev)
{
struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
- u32 val;
if (pcie->of_data->mode == DW_PCIE_EP_TYPE) {
- dev_err(dev, "Failed to Suspend as Tegra PCIe is in EP mode\n");
- return -EPERM;
+ if (pcie->ep_state == EP_STATE_ENABLED) {
+ dev_err(dev, "Tegra PCIe is in EP mode, suspend not allowed\n");
+ return -EPERM;
+ }
+
+ disable_irq(pcie->pex_rst_irq);
+ return 0;
}
+ return 0;
+}
+
+static int tegra_pcie_dw_suspend_late(struct device *dev)
+{
+ struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
+ u32 val;
+
if (!pcie->link_state)
return 0;
@@ -2325,10 +2331,12 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev)
{
struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
+ if (pcie->of_data->mode == DW_PCIE_EP_TYPE)
+ return 0;
+
if (!pcie->link_state)
return 0;
- tegra_pcie_downstream_dev_to_D0(pcie);
tegra_pcie_dw_pme_turnoff(pcie);
tegra_pcie_unconfig_controller(pcie);
@@ -2340,6 +2348,9 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev)
struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
int ret;
+ if (pcie->of_data->mode == DW_PCIE_EP_TYPE)
+ return 0;
+
if (!pcie->link_state)
return 0;
@@ -2372,8 +2383,8 @@ static int tegra_pcie_dw_resume_early(struct device *dev)
u32 val;
if (pcie->of_data->mode == DW_PCIE_EP_TYPE) {
- dev_err(dev, "Suspend is not supported in EP mode");
- return -ENOTSUPP;
+ enable_irq(pcie->pex_rst_irq);
+ return 0;
}
if (!pcie->link_state)
@@ -2402,7 +2413,6 @@ static void tegra_pcie_dw_shutdown(struct platform_device *pdev)
return;
debugfs_remove_recursive(pcie->debugfs);
- tegra_pcie_downstream_dev_to_D0(pcie);
disable_irq(pcie->pci.pp.irq);
if (IS_ENABLED(CONFIG_PCI_MSI))
@@ -2452,6 +2462,7 @@ static const struct tegra_pcie_dw_of_data tegra234_pcie_dw_ep_of_data = {
.mode = DW_PCIE_EP_TYPE,
.has_l1ss_exit_fix = true,
.has_ltr_req_fix = true,
+ .disable_l1_2 = true,
.cdm_chk_int_en_bit = BIT(18),
/* Gen4 - 6, 8 and 9 presets enabled */
.gen4_preset_vec = 0x340,
@@ -2479,6 +2490,7 @@ static const struct of_device_id tegra_pcie_dw_of_match[] = {
};
static const struct dev_pm_ops tegra_pcie_dw_pm_ops = {
+ .suspend = tegra_pcie_dw_suspend,
.suspend_late = tegra_pcie_dw_suspend_late,
.suspend_noirq = tegra_pcie_dw_suspend_noirq,
.resume_noirq = tegra_pcie_dw_resume_noirq,
diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie-aspeed.c
index 3e1a39d1e648..6acfae7d026e 100644
--- a/drivers/pci/controller/pcie-aspeed.c
+++ b/drivers/pci/controller/pcie-aspeed.c
@@ -1052,14 +1052,14 @@ static int aspeed_pcie_probe(struct platform_device *pdev)
if (ret)
return ret;
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
ret = devm_add_action_or_reset(dev, aspeed_pcie_irq_domain_free, pcie);
if (ret)
return ret;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
ret = devm_request_irq(dev, irq, aspeed_pcie_intr_handler, IRQF_SHARED,
dev_name(dev), pcie);
if (ret)
diff --git a/drivers/pci/controller/pcie-mediatek-gen3.c b/drivers/pci/controller/pcie-mediatek-gen3.c
index 75ddb8bee168..e45c43ccc84c 100644
--- a/drivers/pci/controller/pcie-mediatek-gen3.c
+++ b/drivers/pci/controller/pcie-mediatek-gen3.c
@@ -851,14 +851,14 @@ static int mtk_pcie_setup_irq(struct mtk_gen3_pcie *pcie)
struct platform_device *pdev = to_platform_device(dev);
int err;
- err = mtk_pcie_init_irq_domains(pcie);
- if (err)
- return err;
-
pcie->irq = platform_get_irq(pdev, 0);
if (pcie->irq < 0)
return pcie->irq;
+ err = mtk_pcie_init_irq_domains(pcie);
+ if (err)
+ return err;
+
irq_set_chained_handler_and_data(pcie->irq, mtk_pcie_irq_handler, pcie);
return 0;
diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c
index 2809112e6317..986f0a319b3c 100644
--- a/drivers/pci/controller/pcie-rzg3s-host.c
+++ b/drivers/pci/controller/pcie-rzg3s-host.c
@@ -1589,8 +1589,7 @@ static int rzg3s_pcie_probe(struct platform_device *pdev)
host_probe_teardown:
rzg3s_pcie_teardown_irqdomain(host);
- reset_control_bulk_deassert(host->data->num_cfg_resets,
- host->cfg_resets);
+ reset_control_bulk_assert(host->data->num_cfg_resets, host->cfg_resets);
rpm_put:
pm_runtime_put_sync(dev);
rpm_disable:
@@ -1625,31 +1624,31 @@ static int rzg3s_pcie_suspend_noirq(struct device *dev)
clk_disable_unprepare(port->refclk);
- ret = reset_control_bulk_assert(data->num_power_resets,
- host->power_resets);
+ ret = reset_control_bulk_assert(data->num_cfg_resets,
+ host->cfg_resets);
if (ret)
goto refclk_restore;
- ret = reset_control_bulk_assert(data->num_cfg_resets,
- host->cfg_resets);
+ ret = reset_control_bulk_assert(data->num_power_resets,
+ host->power_resets);
if (ret)
- goto power_resets_restore;
+ goto cfg_resets_restore;
ret = regmap_update_bits(sysc, RZG3S_SYS_PCIE_RST_RSM_B,
RZG3S_SYS_PCIE_RST_RSM_B_MASK,
FIELD_PREP(RZG3S_SYS_PCIE_RST_RSM_B_MASK, 0));
if (ret)
- goto cfg_resets_restore;
+ goto power_resets_restore;
return 0;
/* Restore the previous state if any error happens */
-cfg_resets_restore:
- reset_control_bulk_deassert(data->num_cfg_resets,
- host->cfg_resets);
power_resets_restore:
reset_control_bulk_deassert(data->num_power_resets,
host->power_resets);
+cfg_resets_restore:
+ reset_control_bulk_deassert(data->num_cfg_resets,
+ host->cfg_resets);
refclk_restore:
clk_prepare_enable(port->refclk);
pm_runtime_resume_and_get(dev);
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 33548935765e..0e7cbcbebf0b 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -715,7 +715,6 @@ static void pci_epf_test_doorbell_cleanup(struct pci_epf_test *epf_test)
struct pci_epf_test_reg *reg = epf_test->reg[epf_test->test_reg_bar];
struct pci_epf *epf = epf_test->epf;
- free_irq(epf->db_msg[0].virq, epf_test);
reg->doorbell_bar = cpu_to_le32(NO_BAR);
pci_epf_free_doorbell(epf);
@@ -759,7 +758,7 @@ static void pci_epf_test_enable_doorbell(struct pci_epf_test *epf_test,
&epf_test->db_bar.phys_addr, &offset);
if (ret)
- goto err_doorbell_cleanup;
+ goto err_free_irq;
reg->doorbell_offset = cpu_to_le32(offset);
@@ -769,12 +768,14 @@ static void pci_epf_test_enable_doorbell(struct pci_epf_test *epf_test,
ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, &epf_test->db_bar);
if (ret)
- goto err_doorbell_cleanup;
+ goto err_free_irq;
status |= STATUS_DOORBELL_ENABLE_SUCCESS;
reg->status = cpu_to_le32(status);
return;
+err_free_irq:
+ free_irq(epf->db_msg[0].virq, epf_test);
err_doorbell_cleanup:
pci_epf_test_doorbell_cleanup(epf_test);
set_status_err:
@@ -794,6 +795,7 @@ static void pci_epf_test_disable_doorbell(struct pci_epf_test *epf_test,
if (bar < BAR_0)
goto set_status_err;
+ free_irq(epf->db_msg[0].virq, epf_test);
pci_epf_test_doorbell_cleanup(epf_test);
/*
diff --git a/drivers/pci/endpoint/functions/pci-epf-vntb.c b/drivers/pci/endpoint/functions/pci-epf-vntb.c
index 65f5bbf28480..c9c7b50587dd 100644
--- a/drivers/pci/endpoint/functions/pci-epf-vntb.c
+++ b/drivers/pci/endpoint/functions/pci-epf-vntb.c
@@ -527,20 +527,20 @@ static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
struct msi_msg *msg;
size_t sz;
int ret;
- int i;
+ int i, req;
ret = pci_epf_alloc_doorbell(epf, ntb->db_count);
if (ret)
return ret;
- for (i = 0; i < ntb->db_count; i++) {
- ret = request_irq(epf->db_msg[i].virq, epf_ntb_doorbell_handler,
+ for (req = 0; req < ntb->db_count; req++) {
+ ret = request_irq(epf->db_msg[req].virq, epf_ntb_doorbell_handler,
0, "pci_epf_vntb_db", ntb);
if (ret) {
dev_err(&epf->dev,
"Failed to request doorbell IRQ: %d\n",
- epf->db_msg[i].virq);
+ epf->db_msg[req].virq);
goto err_free_irq;
}
}
@@ -598,8 +598,8 @@ static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
return 0;
err_free_irq:
- for (i--; i >= 0; i--)
- free_irq(epf->db_msg[i].virq, ntb);
+ for (req--; req >= 0; req--)
+ free_irq(epf->db_msg[req].virq, ntb);
pci_epf_free_doorbell(ntb->epf);
return ret;
diff --git a/drivers/pci/endpoint/pci-ep-msi.c b/drivers/pci/endpoint/pci-ep-msi.c
index 51c19942a81e..1395919571f8 100644
--- a/drivers/pci/endpoint/pci-ep-msi.c
+++ b/drivers/pci/endpoint/pci-ep-msi.c
@@ -50,6 +50,9 @@ int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db)
return -EINVAL;
}
+ if (epf->db_msg)
+ return -EBUSY;
+
domain = of_msi_map_get_device_domain(epc->dev.parent, 0,
DOMAIN_BUS_PLATFORM_MSI);
if (!domain) {
@@ -79,6 +82,8 @@ int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db)
if (ret) {
dev_err(dev, "Failed to allocate MSI\n");
kfree(msg);
+ epf->db_msg = NULL;
+ epf->num_db = 0;
return ret;
}
diff --git a/drivers/pci/npem.c b/drivers/pci/npem.c
index ffeeedf6e311..c51879fcd438 100644
--- a/drivers/pci/npem.c
+++ b/drivers/pci/npem.c
@@ -504,7 +504,7 @@ static int pci_npem_set_led_classdev(struct npem *npem, struct npem_led *nled)
led->brightness_get = brightness_get;
led->max_brightness = 1;
led->default_trigger = "none";
- led->flags = 0;
+ led->flags = LED_HW_PLUGGABLE;
ret = led_classdev_register(&npem->dev->dev, led);
if (ret)
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index dd9075403987..e3f59001785a 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -138,9 +138,11 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
{
struct pci_dynid *dynid;
const struct pci_device_id *found_id = NULL, *ids;
+ int ret;
/* When driver_override is set, only bind to the matching driver */
- if (dev->driver_override && strcmp(dev->driver_override, drv->name))
+ ret = device_match_driver_override(&dev->dev, &drv->driver);
+ if (ret == 0)
return NULL;
/* Look at the dynamic ids first, before the static ones */
@@ -164,7 +166,7 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
* matching.
*/
if (found_id->override_only) {
- if (dev->driver_override)
+ if (ret > 0)
return found_id;
} else {
return found_id;
@@ -172,11 +174,16 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
}
/* driver_override will always match, send a dummy id */
- if (dev->driver_override)
+ if (ret > 0)
return &pci_device_id_any;
return NULL;
}
+static void _pci_free_device(struct device *dev)
+{
+ kfree(to_pci_dev(dev));
+}
+
/**
* new_id_store - sysfs frontend to pci_add_dynid()
* @driver: target device driver
@@ -212,11 +219,13 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf,
pdev->subsystem_vendor = subvendor;
pdev->subsystem_device = subdevice;
pdev->class = class;
+ pdev->dev.release = _pci_free_device;
+ device_initialize(&pdev->dev);
if (pci_match_device(pdrv, pdev))
retval = -EEXIST;
- kfree(pdev);
+ put_device(&pdev->dev);
if (retval)
return retval;
@@ -452,7 +461,7 @@ static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)
static inline bool pci_device_can_probe(struct pci_dev *pdev)
{
return (!pdev->is_virtfn || pdev->physfn->sriov->drivers_autoprobe ||
- pdev->driver_override);
+ device_has_driver_override(&pdev->dev));
}
#else
static inline bool pci_device_can_probe(struct pci_dev *pdev)
@@ -1722,6 +1731,7 @@ static const struct cpumask *pci_device_irq_get_affinity(struct device *dev,
const struct bus_type pci_bus_type = {
.name = "pci",
+ .driver_override = true,
.match = pci_bus_match,
.uevent = pci_uevent,
.probe = pci_device_probe,
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 16eaaf749ba9..a9006cf4e9c8 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -615,33 +615,6 @@ static ssize_t devspec_show(struct device *dev,
static DEVICE_ATTR_RO(devspec);
#endif
-static ssize_t driver_override_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- int ret;
-
- ret = driver_set_override(dev, &pdev->driver_override, buf, count);
- if (ret)
- return ret;
-
- return count;
-}
-
-static ssize_t driver_override_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- ssize_t len;
-
- device_lock(dev);
- len = sysfs_emit(buf, "%s\n", pdev->driver_override);
- device_unlock(dev);
- return len;
-}
-static DEVICE_ATTR_RW(driver_override);
-
static struct attribute *pci_dev_attrs[] = {
&dev_attr_power_state.attr,
&dev_attr_resource.attr,
@@ -669,7 +642,6 @@ static struct attribute *pci_dev_attrs[] = {
#ifdef CONFIG_OF
&dev_attr_devspec.attr,
#endif
- &dev_attr_driver_override.attr,
&dev_attr_ari_enabled.attr,
NULL,
};
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 8e3e4e24c909..9298a461bd30 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3674,8 +3674,7 @@ void pci_acs_init(struct pci_dev *dev)
*/
int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask)
{
- struct pci_bus *bus = dev->bus;
- struct pci_dev *bridge;
+ struct pci_dev *root, *bridge;
u32 cap, ctl2;
/*
@@ -3705,35 +3704,35 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask)
return -EINVAL;
}
- while (bus->parent) {
- bridge = bus->self;
+ root = pcie_find_root_port(dev);
+ if (!root)
+ return -EINVAL;
- pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &cap);
+ pcie_capability_read_dword(root, PCI_EXP_DEVCAP2, &cap);
+ if ((cap & cap_mask) != cap_mask)
+ return -EINVAL;
+ bridge = pci_upstream_bridge(dev);
+ while (bridge != root) {
switch (pci_pcie_type(bridge)) {
- /* Ensure switch ports support AtomicOp routing */
case PCI_EXP_TYPE_UPSTREAM:
- case PCI_EXP_TYPE_DOWNSTREAM:
- if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE))
- return -EINVAL;
- break;
-
- /* Ensure root port supports all the sizes we care about */
- case PCI_EXP_TYPE_ROOT_PORT:
- if ((cap & cap_mask) != cap_mask)
- return -EINVAL;
- break;
- }
-
- /* Ensure upstream ports don't block AtomicOps on egress */
- if (pci_pcie_type(bridge) == PCI_EXP_TYPE_UPSTREAM) {
+ /* Upstream ports must not block AtomicOps on egress */
pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2,
&ctl2);
if (ctl2 & PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK)
return -EINVAL;
+ fallthrough;
+
+ /* All switch ports need to route AtomicOps */
+ case PCI_EXP_TYPE_DOWNSTREAM:
+ pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2,
+ &cap);
+ if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE))
+ return -EINVAL;
+ break;
}
- bus = bus->parent;
+ bridge = pci_upstream_bridge(bridge);
}
pcie_capability_set_word(dev, PCI_EXP_DEVCTL2,
diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c
index fc18349614d7..7605ddd9f0ba 100644
--- a/drivers/pci/pcie/dpc.c
+++ b/drivers/pci/pcie/dpc.c
@@ -256,6 +256,7 @@ static int dpc_get_aer_uncorrect_severity(struct pci_dev *dev,
info->dev[0] = dev;
info->error_dev_num = 1;
+ info->ratelimit_print[0] = 1;
return 1;
}
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index bccc7a4bdd79..b4707640e102 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2488,7 +2488,6 @@ static void pci_release_dev(struct device *dev)
pci_release_of_node(pci_dev);
pcibios_release_device(pci_dev);
pci_bus_put(pci_dev->bus);
- kfree(pci_dev->driver_override);
bitmap_free(pci_dev->dma_alias_mask);
dev_dbg(dev, "device released\n");
kfree(pci_dev);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 61f769aaa2f6..8f2830c6d34f 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -434,6 +434,10 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
dev = add_res->dev;
idx = pci_resource_num(dev, res);
+ /* Skip this resource if not found in head list */
+ if (!res_to_dev_res(head, res))
+ continue;
+
/*
* Skip resource that failed the earlier assignment and is
* not optional as it would just fail again.
@@ -442,10 +446,6 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
!pci_resource_is_optional(dev, idx))
goto out;
- /* Skip this resource if not found in head list */
- if (!res_to_dev_res(head, res))
- continue;
-
res_name = pci_resource_name(dev, idx);
add_size = add_res->add_size;
align = add_res->min_align;
@@ -1333,7 +1333,14 @@ static void pbus_size_mem(struct pci_bus *bus, struct resource *b_res,
r_size = resource_size(r);
size += max(r_size, align);
- aligns[order] += align;
+ /*
+ * If resource's size is larger than its alignment,
+ * some configurations result in an unwanted gap in
+ * the head space that the larger resource cannot
+ * fill.
+ */
+ if (r_size <= align)
+ aligns[order] += align;
if (order > max_order)
max_order = order;
}
@@ -1837,6 +1844,7 @@ static void adjust_bridge_window(struct pci_dev *bridge, struct resource *res,
resource_size_t new_size)
{
resource_size_t add_size, size = resource_size(res);
+ struct pci_dev_resource *dev_res;
if (resource_assigned(res))
return;
@@ -1849,9 +1857,46 @@ static void adjust_bridge_window(struct pci_dev *bridge, struct resource *res,
pci_dbg(bridge, "bridge window %pR extended by %pa\n", res,
&add_size);
} else if (new_size < size) {
+ int idx = pci_resource_num(bridge, res);
+
+ /*
+ * hpio/mmio/mmioprefsize hasn't been included at all? See the
+ * add_size param at the callsites of calculate_memsize().
+ */
+ if (!add_list)
+ return;
+
+ /* Only shrink if the hotplug extra relates to window size. */
+ switch (idx) {
+ case PCI_BRIDGE_IO_WINDOW:
+ if (size > pci_hotplug_io_size)
+ return;
+ break;
+ case PCI_BRIDGE_MEM_WINDOW:
+ if (size > pci_hotplug_mmio_size)
+ return;
+ break;
+ case PCI_BRIDGE_PREF_MEM_WINDOW:
+ if (size > pci_hotplug_mmio_pref_size)
+ return;
+ break;
+ default:
+ break;
+ }
+
+ dev_res = res_to_dev_res(add_list, res);
add_size = size - new_size;
- pci_dbg(bridge, "bridge window %pR shrunken by %pa\n", res,
- &add_size);
+ if (add_size < dev_res->add_size) {
+ dev_res->add_size -= add_size;
+ pci_dbg(bridge, "bridge window %pR optional size shrunken by %pa\n",
+ res, &add_size);
+ } else {
+ pci_dbg(bridge, "bridge window %pR optional size removed\n",
+ res);
+ pci_dev_res_remove_from_list(add_list, res);
+ }
+ return;
+
} else {
return;
}
diff --git a/drivers/pci/tph.c b/drivers/pci/tph.c
index ca4f97be7538..e896b3958281 100644
--- a/drivers/pci/tph.c
+++ b/drivers/pci/tph.c
@@ -407,10 +407,13 @@ int pcie_enable_tph(struct pci_dev *pdev, int mode)
else
pdev->tph_req_type = PCI_TPH_REQ_TPH_ONLY;
- rp_req_type = get_rp_completer_type(pdev);
+ /* Check if the device is behind a Root Port */
+ if (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_END) {
+ rp_req_type = get_rp_completer_type(pdev);
- /* Final req_type is the smallest value of two */
- pdev->tph_req_type = min(pdev->tph_req_type, rp_req_type);
+ /* Final req_type is the smallest value of two */
+ pdev->tph_req_type = min(pdev->tph_req_type, rp_req_type);
+ }
if (pdev->tph_req_type == PCI_TPH_REQ_DISABLE)
return -EINVAL;
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index 0679dd434719..b28d754ba414 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -187,7 +187,7 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
int any;
u_char *b, hole, most;
- dev_info(&s->dev, "cs: IO port probe %#x-%#x:", base, base+num-1);
+ pr_info("%s: cs: IO port probe %#x-%#x:", dev_name(&s->dev), base, base+num-1);
/* First, what does a floating port look like? */
b = kzalloc(256, GFP_KERNEL);
@@ -409,8 +409,8 @@ static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num,
struct socket_data *s_data = s->resource_data;
u_long i, j, bad, fail, step;
- dev_info(&s->dev, "cs: memory probe 0x%06lx-0x%06lx:",
- base, base+num-1);
+ pr_info("%s: cs: memory probe 0x%06lx-0x%06lx:",
+ dev_name(&s->dev), base, base+num-1);
bad = fail = 0;
step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
/* don't allow too large steps */
diff --git a/drivers/phy/apple/atc.c b/drivers/phy/apple/atc.c
index dc867f368b68..64d0c3dba1cb 100644
--- a/drivers/phy/apple/atc.c
+++ b/drivers/phy/apple/atc.c
@@ -2202,14 +2202,16 @@ static int atcphy_map_resources(struct platform_device *pdev, struct apple_atcph
{ "pipehandler", &atcphy->regs.pipehandler, NULL },
};
struct resource *res;
+ void __iomem *addr;
for (int i = 0; i < ARRAY_SIZE(resources); i++) {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, resources[i].name);
- *resources[i].addr = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(resources[i].addr))
- return dev_err_probe(atcphy->dev, PTR_ERR(resources[i].addr),
+ addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(addr))
+ return dev_err_probe(atcphy->dev, PTR_ERR(addr),
"Unable to map %s regs", resources[i].name);
+ *resources[i].addr = addr;
if (resources[i].res)
*resources[i].res = res;
}
diff --git a/drivers/pinctrl/microchip/pinctrl-mpfs-mssio.c b/drivers/pinctrl/microchip/pinctrl-mpfs-mssio.c
index 3d5ffd6cb14b..15d73ea1028c 100644
--- a/drivers/pinctrl/microchip/pinctrl-mpfs-mssio.c
+++ b/drivers/pinctrl/microchip/pinctrl-mpfs-mssio.c
@@ -686,7 +686,7 @@ static int mpfs_pinctrl_probe(struct platform_device *pdev)
pctrl->regmap = device_node_to_regmap(pdev->dev.parent->of_node);
if (IS_ERR(pctrl->regmap))
- dev_err_probe(dev, PTR_ERR(pctrl->regmap), "Failed to find syscon regmap\n");
+ return dev_err_probe(dev, PTR_ERR(pctrl->regmap), "Failed to find syscon regmap\n");
pctrl->sysreg_regmap = syscon_regmap_lookup_by_compatible("microchip,mpfs-sysreg-scb");
if (IS_ERR(pctrl->sysreg_regmap))
diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c
index fc7ebeda8440..858fbaebcf8e 100644
--- a/drivers/pinctrl/nomadik/pinctrl-abx500.c
+++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c
@@ -852,7 +852,7 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev,
int ret = -EINVAL;
int i;
enum pin_config_param param;
- enum pin_config_param argument;
+ unsigned int argument;
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
index 2b030bd0e6ad..6b4a794a362c 100644
--- a/drivers/pinctrl/pinconf-generic.c
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -287,12 +287,17 @@ int pinconf_generic_parse_dt_pinmux(struct device_node *np, struct device *dev,
return -ENOENT;
}
+ npins_t = prop->length / sizeof(u32);
+ if (npins_t == 0) {
+ dev_info(dev, "pinmux property doesn't have entries\n");
+ return -ENODATA;
+ }
+
if (!pid || !pmux || !npins) {
dev_err(dev, "parameters error\n");
return -EINVAL;
}
- npins_t = prop->length / sizeof(u32);
pid_t = devm_kcalloc(dev, npins_t, sizeof(*pid_t), GFP_KERNEL);
pmux_t = devm_kcalloc(dev, npins_t, sizeof(*pmux_t), GFP_KERNEL);
if (!pid_t || !pmux_t) {
diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c
index 5c055d344ac9..54b117f32f0e 100644
--- a/drivers/pinctrl/pinctrl-cy8c95x0.c
+++ b/drivers/pinctrl/pinctrl-cy8c95x0.c
@@ -1310,6 +1310,7 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq)
{
struct gpio_irq_chip *girq = &chip->gpio_chip.irq;
DECLARE_BITMAP(pending_irqs, MAX_LINE);
+ struct device *dev = chip->dev;
int ret;
mutex_init(&chip->irq_lock);
@@ -1318,10 +1319,8 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq)
/* Read IRQ status register to clear all pending interrupts */
ret = cy8c95x0_irq_pending(chip, pending_irqs);
- if (ret) {
- dev_err(chip->dev, "failed to clear irq status register\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, -EBUSY, "failed to clear irq status register\n");
/* Mask all interrupts */
bitmap_fill(chip->irq_mask, MAX_LINE);
@@ -1336,17 +1335,9 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq)
girq->handler = handle_simple_irq;
girq->threaded = true;
- ret = devm_request_threaded_irq(chip->dev, irq,
- NULL, cy8c95x0_irq_handler,
- IRQF_ONESHOT | IRQF_SHARED,
- dev_name(chip->dev), chip);
- if (ret) {
- dev_err(chip->dev, "failed to request irq %d\n", irq);
- return ret;
- }
- dev_info(chip->dev, "Registered threaded IRQ\n");
-
- return 0;
+ return devm_request_threaded_irq(dev, irq, NULL, cy8c95x0_irq_handler,
+ IRQF_ONESHOT | IRQF_SHARED,
+ dev_name(chip->dev), chip);
}
static int cy8c95x0_setup_pinctrl(struct cy8c95x0_pinctrl *chip)
@@ -1362,11 +1353,7 @@ static int cy8c95x0_setup_pinctrl(struct cy8c95x0_pinctrl *chip)
pd->owner = THIS_MODULE;
chip->pctldev = devm_pinctrl_register(chip->dev, pd, chip);
- if (IS_ERR(chip->pctldev))
- return dev_err_probe(chip->dev, PTR_ERR(chip->pctldev),
- "can't register controller\n");
-
- return 0;
+ return PTR_ERR_OR_ZERO(chip->pctldev);
}
static int cy8c95x0_detect(struct i2c_client *client,
diff --git a/drivers/pinctrl/pinctrl-pic32.c b/drivers/pinctrl/pinctrl-pic32.c
index 16bbbcf72062..f61ab89bc0f7 100644
--- a/drivers/pinctrl/pinctrl-pic32.c
+++ b/drivers/pinctrl/pinctrl-pic32.c
@@ -2174,16 +2174,10 @@ static int pic32_pinctrl_probe(struct platform_device *pdev)
if (IS_ERR(pctl->reg_base))
return PTR_ERR(pctl->reg_base);
- pctl->clk = devm_clk_get(&pdev->dev, NULL);
+ pctl->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(pctl->clk)) {
ret = PTR_ERR(pctl->clk);
- dev_err(&pdev->dev, "clk get failed\n");
- return ret;
- }
-
- ret = clk_prepare_enable(pctl->clk);
- if (ret) {
- dev_err(&pdev->dev, "clk enable failed\n");
+ dev_err(&pdev->dev, "Failed to get and enable clock\n");
return ret;
}
@@ -2239,16 +2233,10 @@ static int pic32_gpio_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- bank->clk = devm_clk_get(&pdev->dev, NULL);
+ bank->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(bank->clk)) {
ret = PTR_ERR(bank->clk);
- dev_err(&pdev->dev, "clk get failed\n");
- return ret;
- }
-
- ret = clk_prepare_enable(bank->clk);
- if (ret) {
- dev_err(&pdev->dev, "clk enable failed\n");
+ dev_err(&pdev->dev, "Failed to get and enable clock\n");
return ret;
}
diff --git a/drivers/pinctrl/realtek/pinctrl-rtd.c b/drivers/pinctrl/realtek/pinctrl-rtd.c
index 244060486332..4c876d1f6ad5 100644
--- a/drivers/pinctrl/realtek/pinctrl-rtd.c
+++ b/drivers/pinctrl/realtek/pinctrl-rtd.c
@@ -279,7 +279,7 @@ static const struct rtd_pin_sconfig_desc *rtd_pinctrl_find_sconfig(struct rtd_pi
static int rtd_pconf_parse_conf(struct rtd_pinctrl *data,
unsigned int pinnr,
enum pin_config_param param,
- enum pin_config_param arg)
+ unsigned int arg)
{
const struct rtd_pin_config_desc *config_desc;
const struct rtd_pin_sconfig_desc *sconfig_desc;
diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
index 863e779dda02..55e35f63343c 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
@@ -3012,6 +3012,13 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen
off = RZG2L_PIN_CFG_TO_PORT_OFFSET(cfg);
pincnt = hweight8(FIELD_GET(PIN_CFG_PIN_MAP_MASK, cfg));
+ if (cfg & RZG2L_VARIABLE_CFG) {
+ unsigned int pin = port * RZG2L_PINS_PER_PORT;
+
+ for (unsigned int i = 0; i < RZG2L_PINS_PER_PORT; i++)
+ cfg |= *(u64 *)pctrl->desc.pins[pin + i].drv_data;
+ }
+
caps = FIELD_GET(PIN_CFG_MASK, cfg);
has_iolh = !!(caps & (PIN_CFG_IOLH_A | PIN_CFG_IOLH_B | PIN_CFG_IOLH_C));
has_ien = !!(caps & PIN_CFG_IEN);
diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2042.c b/drivers/pinctrl/sophgo/pinctrl-sg2042.c
index 185305ac897d..8dba12e122a4 100644
--- a/drivers/pinctrl/sophgo/pinctrl-sg2042.c
+++ b/drivers/pinctrl/sophgo/pinctrl-sg2042.c
@@ -651,5 +651,5 @@ static struct platform_driver sg2042_pinctrl_driver = {
};
module_platform_driver(sg2042_pinctrl_driver);
-MODULE_DESCRIPTION("Pinctrl driver for the SG2002 series SoC");
+MODULE_DESCRIPTION("Pinctrl driver for the SG2042 series SoC");
MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2044.c b/drivers/pinctrl/sophgo/pinctrl-sg2044.c
index b0c46d8954ca..cf0b674c038f 100644
--- a/drivers/pinctrl/sophgo/pinctrl-sg2044.c
+++ b/drivers/pinctrl/sophgo/pinctrl-sg2044.c
@@ -714,5 +714,5 @@ static struct platform_driver sg2044_pinctrl_driver = {
};
module_platform_driver(sg2044_pinctrl_driver);
-MODULE_DESCRIPTION("Pinctrl driver for the SG2002 series SoC");
+MODULE_DESCRIPTION("Pinctrl driver for the SG2044 series SoC");
MODULE_LICENSE("GPL");
diff --git a/drivers/platform/chrome/chromeos_tbmc.c b/drivers/platform/chrome/chromeos_tbmc.c
index d1cf8f3463ce..e248567c0a18 100644
--- a/drivers/platform/chrome/chromeos_tbmc.c
+++ b/drivers/platform/chrome/chromeos_tbmc.c
@@ -95,6 +95,11 @@ static int chromeos_tbmc_add(struct acpi_device *adev)
return 0;
}
+static void chromeos_tbmc_remove(struct acpi_device *adev)
+{
+ device_init_wakeup(&adev->dev, false);
+}
+
static const struct acpi_device_id chromeos_tbmc_acpi_device_ids[] = {
{ ACPI_DRV_NAME, 0 },
{ }
@@ -110,6 +115,7 @@ static struct acpi_driver chromeos_tbmc_driver = {
.ids = chromeos_tbmc_acpi_device_ids,
.ops = {
.add = chromeos_tbmc_add,
+ .remove = chromeos_tbmc_remove,
.notify = chromeos_tbmc_notify,
},
.drv.pm = &chromeos_tbmc_pm_ops,
diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c
index 9bd39f09c7db..a6c9d4d370be 100644
--- a/drivers/platform/surface/surfacepro3_button.c
+++ b/drivers/platform/surface/surfacepro3_button.c
@@ -242,6 +242,7 @@ static void surface_button_remove(struct acpi_device *device)
{
struct surface_button *button = acpi_driver_data(device);
+ device_init_wakeup(&device->dev, false);
input_unregister_device(button->input);
kfree(button);
}
diff --git a/drivers/platform/wmi/core.c b/drivers/platform/wmi/core.c
index b8e6b9a421c6..750e3619724e 100644
--- a/drivers/platform/wmi/core.c
+++ b/drivers/platform/wmi/core.c
@@ -842,39 +842,11 @@ static ssize_t expensive_show(struct device *dev,
}
static DEVICE_ATTR_RO(expensive);
-static ssize_t driver_override_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct wmi_device *wdev = to_wmi_device(dev);
- ssize_t ret;
-
- device_lock(dev);
- ret = sysfs_emit(buf, "%s\n", wdev->driver_override);
- device_unlock(dev);
-
- return ret;
-}
-
-static ssize_t driver_override_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct wmi_device *wdev = to_wmi_device(dev);
- int ret;
-
- ret = driver_set_override(dev, &wdev->driver_override, buf, count);
- if (ret < 0)
- return ret;
-
- return count;
-}
-static DEVICE_ATTR_RW(driver_override);
-
static struct attribute *wmi_attrs[] = {
&dev_attr_modalias.attr,
&dev_attr_guid.attr,
&dev_attr_instance_count.attr,
&dev_attr_expensive.attr,
- &dev_attr_driver_override.attr,
NULL
};
ATTRIBUTE_GROUPS(wmi);
@@ -943,7 +915,6 @@ static void wmi_dev_release(struct device *dev)
{
struct wmi_block *wblock = dev_to_wblock(dev);
- kfree(wblock->dev.driver_override);
kfree(wblock);
}
@@ -952,10 +923,12 @@ static int wmi_dev_match(struct device *dev, const struct device_driver *driver)
const struct wmi_driver *wmi_driver = to_wmi_driver(driver);
struct wmi_block *wblock = dev_to_wblock(dev);
const struct wmi_device_id *id = wmi_driver->id_table;
+ int ret;
/* When driver_override is set, only bind to the matching driver */
- if (wblock->dev.driver_override)
- return !strcmp(wblock->dev.driver_override, driver->name);
+ ret = device_match_driver_override(dev, driver);
+ if (ret >= 0)
+ return ret;
if (id == NULL)
return 0;
@@ -1076,6 +1049,7 @@ static struct class wmi_bus_class = {
static const struct bus_type wmi_bus_type = {
.name = "wmi",
.dev_groups = wmi_groups,
+ .driver_override = true,
.match = wmi_dev_match,
.uevent = wmi_dev_uevent,
.probe = wmi_dev_probe,
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 7c0915e097ba..0f8eb5be7c7a 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -125,7 +125,6 @@ module_param(fnlock_default, bool, 0444);
#define NVIDIA_TEMP_MIN 75
#define NVIDIA_TEMP_MAX 87
-#define ASUS_SCREENPAD_BRIGHT_MIN 20
#define ASUS_SCREENPAD_BRIGHT_MAX 255
#define ASUS_SCREENPAD_BRIGHT_DEFAULT 60
@@ -4408,43 +4407,35 @@ static int read_screenpad_brightness(struct backlight_device *bd)
return err;
/* The device brightness can only be read if powered, so return stored */
if (err == BACKLIGHT_POWER_OFF)
- return asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN;
+ return bd->props.brightness;
err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &retval);
if (err < 0)
return err;
- return (retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK) - ASUS_SCREENPAD_BRIGHT_MIN;
+ return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK;
}
static int update_screenpad_bl_status(struct backlight_device *bd)
{
- struct asus_wmi *asus = bl_get_data(bd);
- int power, err = 0;
- u32 ctrl_param;
+ u32 ctrl_param = bd->props.brightness;
+ int err = 0;
- power = read_screenpad_backlight_power(asus);
- if (power < 0)
- return power;
+ if (bd->props.power) {
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 1, NULL);
+ if (err < 0)
+ return err;
- if (bd->props.power != power) {
- if (power != BACKLIGHT_POWER_ON) {
- /* Only brightness > 0 can power it back on */
- ctrl_param = asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN;
- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT,
- ctrl_param, NULL);
- } else {
- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL);
- }
- } else if (power == BACKLIGHT_POWER_ON) {
- /* Only set brightness if powered on or we get invalid/unsync state */
- ctrl_param = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN;
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, ctrl_param, NULL);
+ if (err < 0)
+ return err;
}
- /* Ensure brightness is stored to turn back on with */
- if (err == 0)
- asus->driver->screenpad_brightness = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN;
+ if (!bd->props.power) {
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL);
+ if (err < 0)
+ return err;
+ }
return err;
}
@@ -4462,22 +4453,19 @@ static int asus_screenpad_init(struct asus_wmi *asus)
int err, power;
int brightness = 0;
- power = read_screenpad_backlight_power(asus);
+ power = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_POWER);
if (power < 0)
return power;
- if (power != BACKLIGHT_POWER_OFF) {
+ if (power) {
err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &brightness);
if (err < 0)
return err;
}
- /* default to an acceptable min brightness on boot if too low */
- if (brightness < ASUS_SCREENPAD_BRIGHT_MIN)
- brightness = ASUS_SCREENPAD_BRIGHT_DEFAULT;
memset(&props, 0, sizeof(struct backlight_properties));
props.type = BACKLIGHT_RAW; /* ensure this bd is last to be picked */
- props.max_brightness = ASUS_SCREENPAD_BRIGHT_MAX - ASUS_SCREENPAD_BRIGHT_MIN;
+ props.max_brightness = ASUS_SCREENPAD_BRIGHT_MAX;
bd = backlight_device_register("asus_screenpad",
&asus->platform_device->dev, asus,
&asus_screenpad_bl_ops, &props);
@@ -4488,7 +4476,7 @@ static int asus_screenpad_init(struct asus_wmi *asus)
asus->screenpad_backlight_device = bd;
asus->driver->screenpad_brightness = brightness;
- bd->props.brightness = brightness - ASUS_SCREENPAD_BRIGHT_MIN;
+ bd->props.brightness = brightness;
bd->props.power = power;
backlight_update_status(bd);
diff --git a/drivers/platform/x86/barco-p50-gpio.c b/drivers/platform/x86/barco-p50-gpio.c
index 6f13e81f98fb..360ffd8505d6 100644
--- a/drivers/platform/x86/barco-p50-gpio.c
+++ b/drivers/platform/x86/barco-p50-gpio.c
@@ -275,8 +275,11 @@ static int p50_gpio_get(struct gpio_chip *gc, unsigned int offset)
mutex_lock(&p50->lock);
ret = p50_send_mbox_cmd(p50, P50_MBOX_CMD_READ_GPIO, gpio_params[offset], 0);
- if (ret == 0)
+ if (ret == 0) {
ret = p50_read_mbox_reg(p50, P50_MBOX_REG_DATA);
+ if (ret >= 0)
+ ret = !!ret;
+ }
mutex_unlock(&p50->lock);
diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c
index 09996fbdc707..a85639d8a076 100644
--- a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c
+++ b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c
@@ -6,10 +6,32 @@
* Copyright (c) 2020 Dell Inc.
*/
+#include <linux/bug.h>
+
#include "dell-wmi-sysman.h"
get_instance_id(enumeration);
+static int append_enum_string(char *dest, const char *src)
+{
+ size_t dest_len = strlen(dest);
+ ssize_t copied;
+
+ if (WARN_ON_ONCE(dest_len >= MAX_BUFF))
+ return -EINVAL;
+
+ copied = strscpy(dest + dest_len, src, MAX_BUFF - dest_len);
+ if (copied < 0)
+ return -EINVAL;
+
+ dest_len += copied;
+ copied = strscpy(dest + dest_len, ";", MAX_BUFF - dest_len);
+ if (copied < 0)
+ return -EINVAL;
+
+ return 0;
+}
+
static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
int instance_id = get_enumeration_instance_id(kobj);
@@ -176,9 +198,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
return -EINVAL;
if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING))
return -EINVAL;
- strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier,
- enumeration_obj[next_obj++].string.pointer);
- strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ";");
+ if (append_enum_string(wmi_priv.enumeration_data[instance_id].dell_value_modifier,
+ enumeration_obj[next_obj++].string.pointer))
+ return -EINVAL;
}
if (next_obj >= enum_property_count)
@@ -193,9 +215,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
return -EINVAL;
if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING))
return -EINVAL;
- strcat(wmi_priv.enumeration_data[instance_id].possible_values,
- enumeration_obj[next_obj++].string.pointer);
- strcat(wmi_priv.enumeration_data[instance_id].possible_values, ";");
+ if (append_enum_string(wmi_priv.enumeration_data[instance_id].possible_values,
+ enumeration_obj[next_obj++].string.pointer))
+ return -EINVAL;
}
return sysfs_create_group(attr_name_kobj, &enumeration_attr_group);
diff --git a/drivers/platform/x86/dell/dell_rbu.c b/drivers/platform/x86/dell/dell_rbu.c
index eb50f1d75d0c..3fa9de9aa47b 100644
--- a/drivers/platform/x86/dell/dell_rbu.c
+++ b/drivers/platform/x86/dell/dell_rbu.c
@@ -30,6 +30,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/init.h>
+#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
@@ -619,9 +620,12 @@ static ssize_t packet_size_write(struct file *filp, struct kobject *kobj,
char *buffer, loff_t pos, size_t count)
{
unsigned long temp;
+
+ if (kstrtoul(buffer, 10, &temp))
+ return -EINVAL;
+
spin_lock(&rbu_data.lock);
packet_empty_list();
- sscanf(buffer, "%lu", &temp);
if (temp < 0xffffffff)
rbu_data.packetsize = temp;
diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c
index 62fd2fe0d8d0..75682bb4cc52 100644
--- a/drivers/platform/x86/hp/hp-wmi.c
+++ b/drivers/platform/x86/hp/hp-wmi.c
@@ -458,23 +458,24 @@ enum pwm_modes {
};
struct hp_wmi_hwmon_priv {
+ struct mutex lock; /* protects mode, pwm */
u8 min_rpm;
u8 max_rpm;
- u8 gpu_delta;
+ int gpu_delta;
u8 mode;
u8 pwm;
struct delayed_work keep_alive_dwork;
};
struct victus_s_fan_table_header {
+ u8 num_fans;
u8 unknown;
- u8 num_entries;
} __packed;
struct victus_s_fan_table_entry {
u8 cpu_rpm;
u8 gpu_rpm;
- u8 unknown;
+ u8 noise_db;
} __packed;
struct victus_s_fan_table {
@@ -2358,13 +2359,16 @@ static int hp_wmi_apply_fan_settings(struct hp_wmi_hwmon_priv *priv)
switch (priv->mode) {
case PWM_MODE_MAX:
- if (is_victus_s_thermal_profile())
- hp_wmi_get_fan_count_userdefine_trigger();
+ if (is_victus_s_thermal_profile()) {
+ ret = hp_wmi_get_fan_count_userdefine_trigger();
+ if (ret < 0)
+ return ret;
+ }
ret = hp_wmi_fan_speed_max_set(1);
if (ret < 0)
return ret;
- schedule_delayed_work(&priv->keep_alive_dwork,
- secs_to_jiffies(KEEP_ALIVE_DELAY_SECS));
+ mod_delayed_work(system_wq, &priv->keep_alive_dwork,
+ secs_to_jiffies(KEEP_ALIVE_DELAY_SECS));
return 0;
case PWM_MODE_MANUAL:
if (!is_victus_s_thermal_profile())
@@ -2372,26 +2376,26 @@ static int hp_wmi_apply_fan_settings(struct hp_wmi_hwmon_priv *priv)
ret = hp_wmi_fan_speed_set(priv, pwm_to_rpm(priv->pwm, priv));
if (ret < 0)
return ret;
- schedule_delayed_work(&priv->keep_alive_dwork,
- secs_to_jiffies(KEEP_ALIVE_DELAY_SECS));
+ mod_delayed_work(system_wq, &priv->keep_alive_dwork,
+ secs_to_jiffies(KEEP_ALIVE_DELAY_SECS));
return 0;
case PWM_MODE_AUTO:
if (is_victus_s_thermal_profile()) {
- hp_wmi_get_fan_count_userdefine_trigger();
+ ret = hp_wmi_get_fan_count_userdefine_trigger();
+ if (ret < 0)
+ return ret;
ret = hp_wmi_fan_speed_max_reset(priv);
} else {
ret = hp_wmi_fan_speed_max_set(0);
}
if (ret < 0)
return ret;
- cancel_delayed_work_sync(&priv->keep_alive_dwork);
+ cancel_delayed_work(&priv->keep_alive_dwork);
return 0;
default:
/* shouldn't happen */
return -EINVAL;
}
-
- return 0;
}
static umode_t hp_wmi_hwmon_is_visible(const void *data,
@@ -2424,6 +2428,7 @@ static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
{
struct hp_wmi_hwmon_priv *priv;
int rpm, ret;
+ u8 mode;
priv = dev_get_drvdata(dev);
switch (type) {
@@ -2447,11 +2452,13 @@ static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
*val = rpm_to_pwm(rpm / 100, priv);
return 0;
}
- switch (priv->mode) {
+ scoped_guard(mutex, &priv->lock)
+ mode = priv->mode;
+ switch (mode) {
case PWM_MODE_MAX:
case PWM_MODE_MANUAL:
case PWM_MODE_AUTO:
- *val = priv->mode;
+ *val = mode;
return 0;
default:
/* shouldn't happen */
@@ -2469,6 +2476,7 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
int rpm;
priv = dev_get_drvdata(dev);
+ guard(mutex)(&priv->lock);
switch (type) {
case hwmon_pwm:
if (attr == hwmon_pwm_input) {
@@ -2533,22 +2541,30 @@ static void hp_wmi_hwmon_keep_alive_handler(struct work_struct *work)
{
struct delayed_work *dwork;
struct hp_wmi_hwmon_priv *priv;
+ int ret;
dwork = to_delayed_work(work);
priv = container_of(dwork, struct hp_wmi_hwmon_priv, keep_alive_dwork);
+
+ guard(mutex)(&priv->lock);
/*
* Re-apply the current hwmon context settings.
* NOTE: hp_wmi_apply_fan_settings will handle the re-scheduling.
*/
- hp_wmi_apply_fan_settings(priv);
+ ret = hp_wmi_apply_fan_settings(priv);
+ if (ret)
+ pr_warn_ratelimited("keep-alive failed to refresh fan settings: %d\n",
+ ret);
}
static int hp_wmi_setup_fan_settings(struct hp_wmi_hwmon_priv *priv)
{
u8 fan_data[128] = { 0 };
struct victus_s_fan_table *fan_table;
- u8 min_rpm, max_rpm, gpu_delta;
- int ret;
+ u8 min_rpm, max_rpm;
+ u8 cpu_rpm, gpu_rpm, noise_db;
+ int gpu_delta, i, num_entries, ret;
+ size_t header_size, entry_size;
/* Default behaviour on hwmon init is automatic mode */
priv->mode = PWM_MODE_AUTO;
@@ -2563,13 +2579,36 @@ static int hp_wmi_setup_fan_settings(struct hp_wmi_hwmon_priv *priv)
return ret;
fan_table = (struct victus_s_fan_table *)fan_data;
- if (fan_table->header.num_entries == 0 ||
- sizeof(struct victus_s_fan_table_header) +
- sizeof(struct victus_s_fan_table_entry) * fan_table->header.num_entries > sizeof(fan_data))
+ if (fan_table->header.num_fans == 0)
+ return -EINVAL;
+
+ header_size = sizeof(struct victus_s_fan_table_header);
+ entry_size = sizeof(struct victus_s_fan_table_entry);
+ num_entries = (sizeof(fan_data) - header_size) / entry_size;
+ min_rpm = U8_MAX;
+ max_rpm = 0;
+
+ for (i = 0 ; i < num_entries ; i++) {
+ cpu_rpm = fan_table->entries[i].cpu_rpm;
+ gpu_rpm = fan_table->entries[i].gpu_rpm;
+ noise_db = fan_table->entries[i].noise_db;
+
+ /*
+ * On some devices, the fan table is truncated with an all-zero row,
+ * hence we stop parsing here.
+ */
+ if (cpu_rpm == 0 && gpu_rpm == 0 && noise_db == 0)
+ break;
+
+ if (cpu_rpm < min_rpm)
+ min_rpm = cpu_rpm;
+ if (cpu_rpm > max_rpm)
+ max_rpm = cpu_rpm;
+ }
+
+ if (min_rpm == U8_MAX || max_rpm == 0)
return -EINVAL;
- min_rpm = fan_table->entries[0].cpu_rpm;
- max_rpm = fan_table->entries[fan_table->header.num_entries - 1].cpu_rpm;
gpu_delta = fan_table->entries[0].gpu_rpm - fan_table->entries[0].cpu_rpm;
priv->min_rpm = min_rpm;
priv->max_rpm = max_rpm;
@@ -2589,6 +2628,10 @@ static int hp_wmi_hwmon_init(void)
if (!priv)
return -ENOMEM;
+ ret = devm_mutex_init(dev, &priv->lock);
+ if (ret)
+ return ret;
+
ret = hp_wmi_setup_fan_settings(priv);
if (ret)
return ret;
@@ -2602,7 +2645,9 @@ static int hp_wmi_hwmon_init(void)
INIT_DELAYED_WORK(&priv->keep_alive_dwork, hp_wmi_hwmon_keep_alive_handler);
platform_set_drvdata(hp_wmi_platform_dev, priv);
- hp_wmi_apply_fan_settings(priv);
+ ret = hp_wmi_apply_fan_settings(priv);
+ if (ret)
+ dev_warn(dev, "Failed to apply initial fan settings: %d\n", ret);
return 0;
}
diff --git a/drivers/platform/x86/intel/vsec_tpmi.c b/drivers/platform/x86/intel/vsec_tpmi.c
index 98846e88d3d0..58ed0ed85e9e 100644
--- a/drivers/platform/x86/intel/vsec_tpmi.c
+++ b/drivers/platform/x86/intel/vsec_tpmi.c
@@ -813,10 +813,6 @@ static int intel_vsec_tpmi_init(struct auxiliary_device *auxdev)
auxiliary_set_drvdata(auxdev, tpmi_info);
- ret = tpmi_create_devices(tpmi_info);
- if (ret)
- return ret;
-
/*
* Allow debugfs when security policy allows. Everything this debugfs
* interface provides, can also be done via /dev/mem access. If
@@ -826,6 +822,12 @@ static int intel_vsec_tpmi_init(struct auxiliary_device *auxdev)
if (!security_locked_down(LOCKDOWN_DEV_MEM) && capable(CAP_SYS_RAWIO))
tpmi_dbgfs_register(tpmi_info);
+ ret = tpmi_create_devices(tpmi_info);
+ if (ret) {
+ debugfs_remove_recursive(tpmi_info->dbgfs_dir);
+ return ret;
+ }
+
return 0;
}
diff --git a/drivers/platform/x86/lenovo/wmi-capdata.c b/drivers/platform/x86/lenovo/wmi-capdata.c
index ee1fb02d8e31..169665be4dcf 100644
--- a/drivers/platform/x86/lenovo/wmi-capdata.c
+++ b/drivers/platform/x86/lenovo/wmi-capdata.c
@@ -27,7 +27,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/acpi.h>
-#include <linux/bitfield.h>
#include <linux/bug.h>
#include <linux/cleanup.h>
#include <linux/component.h>
@@ -48,6 +47,7 @@
#include <linux/wmi.h>
#include "wmi-capdata.h"
+#include "wmi-helpers.h"
#define LENOVO_CAPABILITY_DATA_00_GUID "362A3AFE-3D96-4665-8530-96DAD5BB300E"
#define LENOVO_CAPABILITY_DATA_01_GUID "7A8F5407-CB67-4D6E-B547-39B3BE018154"
@@ -58,9 +58,9 @@
#define LWMI_FEATURE_ID_FAN_TEST 0x05
-#define LWMI_ATTR_ID_FAN_TEST \
- (FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, LWMI_DEVICE_ID_FAN) | \
- FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, LWMI_FEATURE_ID_FAN_TEST))
+#define LWMI_ATTR_ID_FAN_TEST \
+ lwmi_attr_id(LWMI_DEVICE_ID_FAN, LWMI_FEATURE_ID_FAN_TEST, \
+ LWMI_GZ_THERMAL_MODE_NONE, LWMI_TYPE_ID_NONE)
enum lwmi_cd_type {
LENOVO_CAPABILITY_DATA_00,
diff --git a/drivers/platform/x86/lenovo/wmi-capdata.h b/drivers/platform/x86/lenovo/wmi-capdata.h
index 8c1df3efcc55..c3e760b8c3c3 100644
--- a/drivers/platform/x86/lenovo/wmi-capdata.h
+++ b/drivers/platform/x86/lenovo/wmi-capdata.h
@@ -6,6 +6,7 @@
#define _LENOVO_WMI_CAPDATA_H_
#include <linux/bits.h>
+#include <linux/bitfield.h>
#include <linux/types.h>
#define LWMI_SUPP_VALID BIT(0)
@@ -19,6 +20,8 @@
#define LWMI_DEVICE_ID_FAN 0x04
+#define LWMI_TYPE_ID_NONE 0x00
+
struct component_match;
struct device;
struct cd_list;
@@ -57,6 +60,23 @@ struct lwmi_cd_binder {
cd_list_cb_t cd_fan_list_cb;
};
+/**
+ * lwmi_attr_id() - Formats a capability data attribute ID
+ * @dev_id: The u8 corresponding to the device ID.
+ * @feat_id: The u8 corresponding to the feature ID on the device.
+ * @mode_id: The u8 corresponding to the wmi-gamezone mode for set/get.
+ * @type_id: The u8 corresponding to the sub-device.
+ *
+ * Return: encoded capability data attribute ID.
+ */
+static inline u32 lwmi_attr_id(u8 dev_id, u8 feat_id, u8 mode_id, u8 type_id)
+{
+ return (FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, dev_id) |
+ FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, feat_id) |
+ FIELD_PREP(LWMI_ATTR_MODE_ID_MASK, mode_id) |
+ FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, type_id));
+}
+
void lwmi_cd_match_add_all(struct device *master, struct component_match **matchptr);
int lwmi_cd00_get_data(struct cd_list *list, u32 attribute_id, struct capdata00 *output);
int lwmi_cd01_get_data(struct cd_list *list, u32 attribute_id, struct capdata01 *output);
diff --git a/drivers/platform/x86/lenovo/wmi-events.c b/drivers/platform/x86/lenovo/wmi-events.c
index 0994cd7dd504..9e9f2e82e04d 100644
--- a/drivers/platform/x86/lenovo/wmi-events.c
+++ b/drivers/platform/x86/lenovo/wmi-events.c
@@ -17,7 +17,7 @@
#include <linux/wmi.h>
#include "wmi-events.h"
-#include "wmi-gamezone.h"
+#include "wmi-helpers.h"
#define THERMAL_MODE_EVENT_GUID "D320289E-8FEA-41E0-86F9-911D83151B5F"
diff --git a/drivers/platform/x86/lenovo/wmi-gamezone.c b/drivers/platform/x86/lenovo/wmi-gamezone.c
index c7fe7e3c9f17..686d9128b0f1 100644
--- a/drivers/platform/x86/lenovo/wmi-gamezone.c
+++ b/drivers/platform/x86/lenovo/wmi-gamezone.c
@@ -21,7 +21,6 @@
#include <linux/wmi.h>
#include "wmi-events.h"
-#include "wmi-gamezone.h"
#include "wmi-helpers.h"
#include "wmi-other.h"
@@ -201,7 +200,7 @@ static int lwmi_gz_profile_set(struct device *dev,
enum platform_profile_option profile)
{
struct lwmi_gz_priv *priv = dev_get_drvdata(dev);
- struct wmi_method_args_32 args;
+ struct wmi_method_args_32 args = {};
enum thermal_mode mode;
int ret;
diff --git a/drivers/platform/x86/lenovo/wmi-gamezone.h b/drivers/platform/x86/lenovo/wmi-gamezone.h
deleted file mode 100644
index 6b163a5eeb95..000000000000
--- a/drivers/platform/x86/lenovo/wmi-gamezone.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-/* Copyright (C) 2025 Derek J. Clark <derekjohn.clark@gmail.com> */
-
-#ifndef _LENOVO_WMI_GAMEZONE_H_
-#define _LENOVO_WMI_GAMEZONE_H_
-
-enum gamezone_events_type {
- LWMI_GZ_GET_THERMAL_MODE = 1,
-};
-
-enum thermal_mode {
- LWMI_GZ_THERMAL_MODE_QUIET = 0x01,
- LWMI_GZ_THERMAL_MODE_BALANCED = 0x02,
- LWMI_GZ_THERMAL_MODE_PERFORMANCE = 0x03,
- LWMI_GZ_THERMAL_MODE_EXTREME = 0xE0, /* Ver 6+ */
- LWMI_GZ_THERMAL_MODE_CUSTOM = 0xFF,
-};
-
-#endif /* !_LENOVO_WMI_GAMEZONE_H_ */
diff --git a/drivers/platform/x86/lenovo/wmi-helpers.c b/drivers/platform/x86/lenovo/wmi-helpers.c
index 7379defac500..018d7642e2bd 100644
--- a/drivers/platform/x86/lenovo/wmi-helpers.c
+++ b/drivers/platform/x86/lenovo/wmi-helpers.c
@@ -46,7 +46,6 @@ int lwmi_dev_evaluate_int(struct wmi_device *wdev, u8 instance, u32 method_id,
unsigned char *buf, size_t size, u32 *retval)
{
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *ret_obj __free(kfree) = NULL;
struct acpi_buffer input = { size, buf };
acpi_status status;
@@ -55,8 +54,9 @@ int lwmi_dev_evaluate_int(struct wmi_device *wdev, u8 instance, u32 method_id,
if (ACPI_FAILURE(status))
return -EIO;
+ union acpi_object *ret_obj __free(kfree) = output.pointer;
+
if (retval) {
- ret_obj = output.pointer;
if (!ret_obj)
return -ENODATA;
diff --git a/drivers/platform/x86/lenovo/wmi-helpers.h b/drivers/platform/x86/lenovo/wmi-helpers.h
index 20fd21749803..3364d8e152ca 100644
--- a/drivers/platform/x86/lenovo/wmi-helpers.h
+++ b/drivers/platform/x86/lenovo/wmi-helpers.h
@@ -14,6 +14,19 @@ struct wmi_method_args_32 {
u32 arg1;
};
+enum lwmi_event_type {
+ LWMI_GZ_GET_THERMAL_MODE = 0x01,
+};
+
+enum thermal_mode {
+ LWMI_GZ_THERMAL_MODE_NONE = 0x00,
+ LWMI_GZ_THERMAL_MODE_QUIET = 0x01,
+ LWMI_GZ_THERMAL_MODE_BALANCED = 0x02,
+ LWMI_GZ_THERMAL_MODE_PERFORMANCE = 0x03,
+ LWMI_GZ_THERMAL_MODE_EXTREME = 0xE0, /* Ver 6+ */
+ LWMI_GZ_THERMAL_MODE_CUSTOM = 0xFF,
+};
+
int lwmi_dev_evaluate_int(struct wmi_device *wdev, u8 instance, u32 method_id,
unsigned char *buf, size_t size, u32 *retval);
diff --git a/drivers/platform/x86/lenovo/wmi-other.c b/drivers/platform/x86/lenovo/wmi-other.c
index 6040f45aa2b0..d1cab4d5787a 100644
--- a/drivers/platform/x86/lenovo/wmi-other.c
+++ b/drivers/platform/x86/lenovo/wmi-other.c
@@ -47,7 +47,6 @@
#include "wmi-capdata.h"
#include "wmi-events.h"
-#include "wmi-gamezone.h"
#include "wmi-helpers.h"
#include "wmi-other.h"
#include "../firmware_attributes_class.h"
@@ -62,8 +61,6 @@
#define LWMI_FEATURE_ID_FAN_RPM 0x03
-#define LWMI_TYPE_ID_NONE 0x00
-
#define LWMI_FEATURE_VALUE_GET 17
#define LWMI_FEATURE_VALUE_SET 18
@@ -71,13 +68,12 @@
#define LWMI_FAN_NR 4
#define LWMI_FAN_ID(x) ((x) + LWMI_FAN_ID_BASE)
-#define LWMI_ATTR_ID_FAN_RPM(x) \
- (FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, LWMI_DEVICE_ID_FAN) | \
- FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, LWMI_FEATURE_ID_FAN_RPM) | \
- FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, LWMI_FAN_ID(x)))
-
#define LWMI_FAN_DIV 100
+#define LWMI_ATTR_ID_FAN_RPM(x) \
+ lwmi_attr_id(LWMI_DEVICE_ID_FAN, LWMI_FEATURE_ID_FAN_RPM, \
+ LWMI_GZ_THERMAL_MODE_NONE, LWMI_FAN_ID(x))
+
#define LWMI_OM_FW_ATTR_BASE_PATH "lenovo-wmi-other"
#define LWMI_OM_HWMON_NAME "lenovo_wmi_other"
@@ -166,7 +162,7 @@ MODULE_PARM_DESC(relax_fan_constraint,
*/
static int lwmi_om_fan_get_set(struct lwmi_om_priv *priv, int channel, u32 *val, bool set)
{
- struct wmi_method_args_32 args;
+ struct wmi_method_args_32 args = {};
u32 method_id, retval;
int err;
@@ -546,13 +542,26 @@ static void lwmi_om_fan_info_collect_cd_fan(struct device *dev, struct cd_list *
/* ======== fw_attributes (component: lenovo-wmi-capdata 01) ======== */
struct tunable_attr_01 {
- struct capdata01 *capdata;
struct device *dev;
- u32 feature_id;
- u32 device_id;
- u32 type_id;
+ u8 feature_id;
+ u8 device_id;
+ u8 type_id;
+ u8 cd_mode_id; /* mode arg for searching capdata */
+ u8 cv_mode_id; /* mode arg for set/get current_value */
};
+/**
+ * tunable_attr_01_id() - Formats a tunable_attr_01 to a capdata attribute ID
+ * @attr: The tunable_attr_01 to format.
+ * @mode: The u8 corresponding to the wmi-gamezone mode for set/get.
+ *
+ * Return: encoded capability data attribute ID.
+ */
+static u32 tunable_attr_01_id(struct tunable_attr_01 *attr, u8 mode)
+{
+ return lwmi_attr_id(attr->device_id, attr->feature_id, mode, attr->type_id);
+}
+
static struct tunable_attr_01 ppt_pl1_spl = {
.device_id = LWMI_DEVICE_ID_CPU,
.feature_id = LWMI_FEATURE_ID_CPU_SPL,
@@ -716,12 +725,7 @@ static ssize_t attr_capdata01_show(struct kobject *kobj,
u32 attribute_id;
int value, ret;
- attribute_id =
- FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, tunable_attr->device_id) |
- FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, tunable_attr->feature_id) |
- FIELD_PREP(LWMI_ATTR_MODE_ID_MASK,
- LWMI_GZ_THERMAL_MODE_CUSTOM) |
- FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, tunable_attr->type_id);
+ attribute_id = tunable_attr_01_id(tunable_attr, tunable_attr->cd_mode_id);
ret = lwmi_cd01_get_data(priv->cd01_list, attribute_id, &capdata);
if (ret)
@@ -773,10 +777,9 @@ static ssize_t attr_current_value_store(struct kobject *kobj,
struct tunable_attr_01 *tunable_attr)
{
struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev);
- struct wmi_method_args_32 args;
+ struct wmi_method_args_32 args = {};
struct capdata01 capdata;
enum thermal_mode mode;
- u32 attribute_id;
u32 value;
int ret;
@@ -787,13 +790,9 @@ static ssize_t attr_current_value_store(struct kobject *kobj,
if (mode != LWMI_GZ_THERMAL_MODE_CUSTOM)
return -EBUSY;
- attribute_id =
- FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, tunable_attr->device_id) |
- FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, tunable_attr->feature_id) |
- FIELD_PREP(LWMI_ATTR_MODE_ID_MASK, mode) |
- FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, tunable_attr->type_id);
+ args.arg0 = tunable_attr_01_id(tunable_attr, tunable_attr->cd_mode_id);
- ret = lwmi_cd01_get_data(priv->cd01_list, attribute_id, &capdata);
+ ret = lwmi_cd01_get_data(priv->cd01_list, args.arg0, &capdata);
if (ret)
return ret;
@@ -804,7 +803,7 @@ static ssize_t attr_current_value_store(struct kobject *kobj,
if (value < capdata.min_value || value > capdata.max_value)
return -EINVAL;
- args.arg0 = attribute_id;
+ args.arg0 = tunable_attr_01_id(tunable_attr, tunable_attr->cv_mode_id);
args.arg1 = value;
ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_SET,
@@ -836,9 +835,8 @@ static ssize_t attr_current_value_show(struct kobject *kobj,
struct tunable_attr_01 *tunable_attr)
{
struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev);
- struct wmi_method_args_32 args;
+ struct wmi_method_args_32 args = {};
enum thermal_mode mode;
- u32 attribute_id;
int retval;
int ret;
@@ -846,13 +844,11 @@ static ssize_t attr_current_value_show(struct kobject *kobj,
if (ret)
return ret;
- attribute_id =
- FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, tunable_attr->device_id) |
- FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, tunable_attr->feature_id) |
- FIELD_PREP(LWMI_ATTR_MODE_ID_MASK, mode) |
- FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, tunable_attr->type_id);
+ /* If "no-mode" is the supported mode, ensure we never send current mode */
+ if (tunable_attr->cv_mode_id == LWMI_GZ_THERMAL_MODE_NONE)
+ mode = tunable_attr->cv_mode_id;
- args.arg0 = attribute_id;
+ args.arg0 = tunable_attr_01_id(tunable_attr, mode);
ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_GET,
(unsigned char *)&args, sizeof(args),
@@ -863,6 +859,81 @@ static ssize_t attr_current_value_show(struct kobject *kobj,
return sysfs_emit(buf, "%d\n", retval);
}
+/**
+ * lwmi_attr_01_is_supported() - Determine if the given attribute is supported.
+ * @tunable_attr: The attribute to verify.
+ *
+ * For an attribute to be supported it must have a functional get/set method,
+ * as well as associated capability data stored in the capdata01 table.
+ *
+ * First check if the attribute has a corresponding data table under custom mode
+ * (0xff), then under no mode (0x00). If either of those passes, check if the
+ * supported field of the capdata struct is > 0. If it is supported, store the
+ * successful mode in the cd_mode_id field of tunable_attr.
+ *
+ * If the attribute capdata shows it is supported, attempt to determine the mode
+ * for the current value property get/set methods using a similar pattern to the
+ * capdata table check. If the value returned by either mode is 0 or an error,
+ * assume that mode is not supported. Otherwise, store the successful mode in the
+ * cv_mode_id field of tunable_attr.
+ *
+ * If any of the above checks fail then the attribute is not fully supported.
+ *
+ * Return: true if capdata and set/get modes are found, otherwise false.
+ */
+static bool lwmi_attr_01_is_supported(struct tunable_attr_01 *tunable_attr)
+{
+ u8 modes[2] = { LWMI_GZ_THERMAL_MODE_CUSTOM, LWMI_GZ_THERMAL_MODE_NONE };
+ struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev);
+ struct wmi_method_args_32 args = {};
+ bool cd_mode_found = false;
+ bool cv_mode_found = false;
+ struct capdata01 capdata;
+ int retval, ret, i;
+
+ /* Determine tunable_attr->cd_mode_id */
+ for (i = 0; i < ARRAY_SIZE(modes); i++) {
+ args.arg0 = tunable_attr_01_id(tunable_attr, modes[i]);
+
+ ret = lwmi_cd01_get_data(priv->cd01_list, args.arg0, &capdata);
+ if (ret || !capdata.supported)
+ continue;
+
+ tunable_attr->cd_mode_id = modes[i];
+ cd_mode_found = true;
+ break;
+ }
+
+ if (!cd_mode_found)
+ return cd_mode_found;
+
+ dev_dbg(tunable_attr->dev,
+ "cd_mode_id: %#010x\n", args.arg0);
+
+ /* Determine tunable_attr->cv_mode_id, returns 1 if supported */
+ for (i = 0; i < ARRAY_SIZE(modes); i++) {
+ args.arg0 = tunable_attr_01_id(tunable_attr, modes[i]);
+
+ ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_GET,
+ (u8 *)&args, sizeof(args),
+ &retval);
+ if (ret || !retval)
+ continue;
+
+ tunable_attr->cv_mode_id = modes[i];
+ cv_mode_found = true;
+ break;
+ }
+
+ if (!cv_mode_found)
+ return cv_mode_found;
+
+ dev_dbg(tunable_attr->dev, "cv_mode_id: %#010x, attribute support level: %#010x\n",
+ args.arg0, capdata.supported);
+
+ return capdata.supported > 0;
+}
+
/* Lenovo WMI Other Mode Attribute macros */
#define __LWMI_ATTR_RO(_func, _name) \
{ \
@@ -957,17 +1028,17 @@ static struct capdata01_attr_group cd01_attr_groups[] = {
/**
* lwmi_om_fw_attr_add() - Register all firmware_attributes_class members
* @priv: The Other Mode driver data.
- *
- * Return: Either 0, or an error code.
*/
-static int lwmi_om_fw_attr_add(struct lwmi_om_priv *priv)
+static void lwmi_om_fw_attr_add(struct lwmi_om_priv *priv)
{
unsigned int i;
int err;
- priv->ida_id = ida_alloc(&lwmi_om_ida, GFP_KERNEL);
- if (priv->ida_id < 0)
- return priv->ida_id;
+ err = ida_alloc(&lwmi_om_ida, GFP_KERNEL);
+ if (err < 0)
+ goto err_no_ida;
+
+ priv->ida_id = err;
priv->fw_attr_dev = device_create(&firmware_attributes_class, NULL,
MKDEV(0, 0), NULL, "%s-%u",
@@ -986,14 +1057,16 @@ static int lwmi_om_fw_attr_add(struct lwmi_om_priv *priv)
}
for (i = 0; i < ARRAY_SIZE(cd01_attr_groups) - 1; i++) {
+ cd01_attr_groups[i].tunable_attr->dev = &priv->wdev->dev;
+ if (!lwmi_attr_01_is_supported(cd01_attr_groups[i].tunable_attr))
+ continue;
+
err = sysfs_create_group(&priv->fw_attr_kset->kobj,
cd01_attr_groups[i].attr_group);
if (err)
goto err_remove_groups;
-
- cd01_attr_groups[i].tunable_attr->dev = &priv->wdev->dev;
}
- return 0;
+ return;
err_remove_groups:
while (i--)
@@ -1007,7 +1080,12 @@ static int lwmi_om_fw_attr_add(struct lwmi_om_priv *priv)
err_free_ida:
ida_free(&lwmi_om_ida, priv->ida_id);
- return err;
+
+err_no_ida:
+ priv->ida_id = -EIDRM;
+
+ dev_warn(&priv->wdev->dev,
+ "failed to register firmware-attributes device: %d\n", err);
}
/**
@@ -1016,12 +1094,17 @@ static int lwmi_om_fw_attr_add(struct lwmi_om_priv *priv)
*/
static void lwmi_om_fw_attr_remove(struct lwmi_om_priv *priv)
{
+ if (priv->ida_id < 0)
+ return;
+
for (unsigned int i = 0; i < ARRAY_SIZE(cd01_attr_groups) - 1; i++)
sysfs_remove_group(&priv->fw_attr_kset->kobj,
cd01_attr_groups[i].attr_group);
kset_unregister(priv->fw_attr_kset);
device_unregister(priv->fw_attr_dev);
+ ida_free(&lwmi_om_ida, priv->ida_id);
+ priv->ida_id = -EIDRM;
}
/* ======== Self (master: lenovo-wmi-other) ======== */
@@ -1058,12 +1141,17 @@ static int lwmi_om_master_bind(struct device *dev)
priv->cd00_list = binder.cd00_list;
priv->cd01_list = binder.cd01_list;
- if (!priv->cd00_list || !priv->cd01_list)
+ if (!priv->cd00_list || !priv->cd01_list) {
+ component_unbind_all(dev, NULL);
+
return -ENODEV;
+ }
lwmi_om_fan_info_collect_cd00(priv);
- return lwmi_om_fw_attr_add(priv);
+ lwmi_om_fw_attr_add(priv);
+
+ return 0;
}
/**
@@ -1115,13 +1203,7 @@ static int lwmi_other_probe(struct wmi_device *wdev, const void *context)
static void lwmi_other_remove(struct wmi_device *wdev)
{
- struct lwmi_om_priv *priv = dev_get_drvdata(&wdev->dev);
-
component_master_del(&wdev->dev, &lwmi_om_master_ops);
-
- /* No IDA to free if the driver is never bound to its components. */
- if (priv->ida_id >= 0)
- ida_free(&lwmi_om_ida, priv->ida_id);
}
static const struct wmi_device_id lwmi_other_id_table[] = {
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index d923ddaa4849..97c0c51b5a4c 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -1093,9 +1093,10 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
}
result = device_create_file(&pcc->platform->dev,
&dev_attr_cdpower);
- pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD");
if (result)
goto out_platform;
+
+ pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD");
} else {
pcc->platform = NULL;
}
@@ -1129,10 +1130,10 @@ static void acpi_pcc_hotkey_remove(struct acpi_device *device)
i8042_remove_filter(panasonic_i8042_filter);
if (pcc->platform) {
+ pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD");
device_remove_file(&pcc->platform->dev, &dev_attr_cdpower);
platform_device_unregister(pcc->platform);
}
- pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD");
sysfs_remove_group(&device->dev.kobj, &pcc_attr_group);
diff --git a/drivers/pmdomain/imx/scu-pd.c b/drivers/pmdomain/imx/scu-pd.c
index 01d465d88f60..3ec33667a308 100644
--- a/drivers/pmdomain/imx/scu-pd.c
+++ b/drivers/pmdomain/imx/scu-pd.c
@@ -326,6 +326,7 @@ static void imx_sc_pd_get_console_rsrc(void)
return;
imx_con_rsrc = specs.args[0];
+ of_node_put(specs.np);
}
static int imx_sc_get_pd_power(struct device *dev, u32 rsrc)
diff --git a/drivers/pmdomain/ti/omap_prm.c b/drivers/pmdomain/ti/omap_prm.c
index 5142f064bf5c..64a187f79a1a 100644
--- a/drivers/pmdomain/ti/omap_prm.c
+++ b/drivers/pmdomain/ti/omap_prm.c
@@ -655,6 +655,7 @@ static int omap_prm_domain_attach_dev(struct generic_pm_domain *domain,
if (pd_args.args_count != 0)
dev_warn(dev, "%s: unusupported #power-domain-cells: %i\n",
prmd->pd.name, pd_args.args_count);
+ of_node_put(pd_args.np);
genpd_data = dev_gpd_data(dev);
genpd_data->data = NULL;
diff --git a/drivers/power/supply/max77705_charger.c b/drivers/power/supply/max77705_charger.c
index 5dd02f658f5b..63b0b4f0cd21 100644
--- a/drivers/power/supply/max77705_charger.c
+++ b/drivers/power/supply/max77705_charger.c
@@ -646,51 +646,37 @@ static int max77705_charger_probe(struct i2c_client *i2c)
if (ret)
return dev_err_probe(dev, ret, "failed to add irq chip\n");
- chg->wqueue = create_singlethread_workqueue(dev_name(dev));
+ chg->wqueue = devm_alloc_ordered_workqueue(dev, "%s", 0, dev_name(dev));
if (!chg->wqueue)
return -ENOMEM;
ret = devm_work_autocancel(dev, &chg->chgin_work, max77705_chgin_isr_work);
- if (ret) {
- dev_err_probe(dev, ret, "failed to initialize interrupt work\n");
- goto destroy_wq;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to initialize interrupt work\n");
ret = max77705_charger_initialize(chg);
- if (ret) {
- dev_err_probe(dev, ret, "failed to initialize charger IC\n");
- goto destroy_wq;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to initialize charger IC\n");
ret = devm_request_threaded_irq(dev, regmap_irq_get_virq(irq_data, MAX77705_CHGIN_I),
NULL, max77705_chgin_irq,
IRQF_TRIGGER_NONE,
"chgin-irq", chg);
- if (ret) {
- dev_err_probe(dev, ret, "Failed to Request chgin IRQ\n");
- goto destroy_wq;
- }
+ if (ret)
+ return ret;
ret = devm_request_threaded_irq(dev, regmap_irq_get_virq(irq_data, MAX77705_AICL_I),
NULL, max77705_aicl_irq,
IRQF_TRIGGER_NONE,
"aicl-irq", chg);
- if (ret) {
- dev_err_probe(dev, ret, "Failed to Request aicl IRQ\n");
- goto destroy_wq;
- }
+ if (ret)
+ return ret;
ret = max77705_charger_enable(chg);
- if (ret) {
- dev_err_probe(dev, ret, "failed to enable charge\n");
- goto destroy_wq;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to enable charge\n");
return devm_add_action_or_reset(dev, max77705_charger_disable, chg);
-
-destroy_wq:
- destroy_workqueue(chg->wqueue);
- return ret;
}
static const struct of_device_id max77705_charger_of_match[] = {
diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c
index f9ff78ba122d..3d30aeab507e 100644
--- a/drivers/pwm/pwm-atmel-tcb.c
+++ b/drivers/pwm/pwm-atmel-tcb.c
@@ -50,6 +50,8 @@ struct atmel_tcb_pwm_chip {
spinlock_t lock;
u8 channel;
u8 width;
+ unsigned long rate;
+ unsigned long slow_rate;
struct regmap *regmap;
struct clk *clk;
struct clk *gclk;
@@ -266,7 +268,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
int slowclk = 0;
unsigned period;
unsigned duty;
- unsigned rate = clk_get_rate(tcbpwmc->clk);
+ unsigned long rate = tcbpwmc->rate;
unsigned long long min;
unsigned long long max;
@@ -294,7 +296,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
*/
if (i == ARRAY_SIZE(atmel_tcb_divisors)) {
i = slowclk;
- rate = clk_get_rate(tcbpwmc->slow_clk);
+ rate = tcbpwmc->slow_rate;
min = div_u64(NSEC_PER_SEC, rate);
max = min << tcbpwmc->width;
@@ -431,24 +433,49 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
}
chip->ops = &atmel_tcb_pwm_ops;
+ chip->atomic = true;
tcbpwmc->channel = channel;
tcbpwmc->width = config->counter_width;
- err = clk_prepare_enable(tcbpwmc->slow_clk);
+ err = clk_prepare_enable(tcbpwmc->clk);
if (err)
goto err_gclk;
+ err = clk_prepare_enable(tcbpwmc->slow_clk);
+ if (err)
+ goto err_disable_clk;;
+
+ err = clk_rate_exclusive_get(tcbpwmc->clk);
+ if (err)
+ goto err_disable_slow_clk;
+
+ err = clk_rate_exclusive_get(tcbpwmc->slow_clk);
+ if (err)
+ goto err_clk_unlock;
+
+ tcbpwmc->rate = clk_get_rate(tcbpwmc->clk);
+ tcbpwmc->slow_rate = clk_get_rate(tcbpwmc->slow_clk);
+
spin_lock_init(&tcbpwmc->lock);
err = pwmchip_add(chip);
if (err < 0)
- goto err_disable_clk;
+ goto err_slow_clk_unlock;
platform_set_drvdata(pdev, chip);
return 0;
+err_slow_clk_unlock:
+ clk_rate_exclusive_put(tcbpwmc->slow_clk);
+
+err_clk_unlock:
+ clk_rate_exclusive_put(tcbpwmc->clk);
+
err_disable_clk:
+ clk_disable_unprepare(tcbpwmc->clk);
+
+err_disable_slow_clk:
clk_disable_unprepare(tcbpwmc->slow_clk);
err_gclk:
@@ -470,6 +497,9 @@ static void atmel_tcb_pwm_remove(struct platform_device *pdev)
pwmchip_remove(chip);
+ clk_rate_exclusive_put(tcbpwmc->slow_clk);
+ clk_rate_exclusive_put(tcbpwmc->clk);
+ clk_disable_unprepare(tcbpwmc->clk);
clk_disable_unprepare(tcbpwmc->slow_clk);
clk_put(tcbpwmc->gclk);
clk_put(tcbpwmc->clk);
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
index 2594fb771b04..935257a890b0 100644
--- a/drivers/pwm/pwm-stm32.c
+++ b/drivers/pwm/pwm-stm32.c
@@ -68,7 +68,7 @@ static int stm32_pwm_round_waveform_tohw(struct pwm_chip *chip,
struct stm32_pwm *priv = to_stm32_pwm_dev(chip);
unsigned int ch = pwm->hwpwm;
unsigned long rate;
- u64 ccr, duty;
+ u64 duty_ticks, offset_ticks;
int ret;
if (wf->period_length_ns == 0) {
@@ -164,23 +164,25 @@ static int stm32_pwm_round_waveform_tohw(struct pwm_chip *chip,
wfhw->arr = min_t(u64, arr, priv->max_arr) - 1;
}
- duty = mul_u64_u64_div_u64(wf->duty_length_ns, rate,
- (u64)NSEC_PER_SEC * (wfhw->psc + 1));
- duty = min_t(u64, duty, wfhw->arr + 1);
+ duty_ticks = mul_u64_u64_div_u64(wf->duty_length_ns, rate,
+ (u64)NSEC_PER_SEC * (wfhw->psc + 1));
+ duty_ticks = min_t(u64, duty_ticks, wfhw->arr + 1);
- if (wf->duty_length_ns && wf->duty_offset_ns &&
- wf->duty_length_ns + wf->duty_offset_ns >= wf->period_length_ns) {
+ offset_ticks = mul_u64_u64_div_u64(wf->duty_offset_ns, rate,
+ (u64)NSEC_PER_SEC * (wfhw->psc + 1));
+ offset_ticks = min_t(u64, offset_ticks, wfhw->arr + 1);
+
+ if (duty_ticks && offset_ticks &&
+ duty_ticks + offset_ticks >= wfhw->arr + 1) {
wfhw->ccer |= TIM_CCER_CCxP(ch + 1);
if (priv->have_complementary_output)
wfhw->ccer |= TIM_CCER_CCxNP(ch + 1);
- ccr = wfhw->arr + 1 - duty;
+ wfhw->ccr = wfhw->arr + 1 - duty_ticks;
} else {
- ccr = duty;
+ wfhw->ccr = duty_ticks;
}
- wfhw->ccr = min_t(u64, ccr, wfhw->arr + 1);
-
out:
dev_dbg(&chip->dev, "pwm#%u: %lld/%lld [+%lld] @%lu -> CCER: %08x, PSC: %08x, ARR: %08x, CCR: %08x\n",
pwm->hwpwm, wf->duty_length_ns, wf->period_length_ns, wf->duty_offset_ns,
diff --git a/drivers/regulator/fp9931.c b/drivers/regulator/fp9931.c
index abea3b69d8a0..002b41f53eff 100644
--- a/drivers/regulator/fp9931.c
+++ b/drivers/regulator/fp9931.c
@@ -446,7 +446,7 @@ static int fp9931_probe(struct i2c_client *client)
return dev_err_probe(&client->dev, PTR_ERR(data->regmap),
"failed to allocate regmap!\n");
- data->vin_reg = devm_regulator_get_optional(&client->dev, "vin");
+ data->vin_reg = devm_regulator_get(&client->dev, "vin");
if (IS_ERR(data->vin_reg))
return dev_err_probe(&client->dev, PTR_ERR(data->vin_reg),
"failed to get vin regulator\n");
diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 23126bc22705..0dd80e688b0e 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -1007,7 +1007,11 @@ static int imx_rproc_mmio_detect_mode(struct rproc *rproc)
}
priv->regmap = regmap;
- regmap_attach_dev(dev, regmap, &config);
+ ret = regmap_attach_dev(dev, regmap, &config);
+ if (ret) {
+ dev_err(dev, "regmap attach failed\n");
+ return ret;
+ }
if (priv->gpr) {
ret = regmap_read(priv->gpr, dcfg->gpr_reg, &val);
diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c
index f949749e50b0..eb5f714de2bf 100644
--- a/drivers/remoteproc/xlnx_r5_remoteproc.c
+++ b/drivers/remoteproc/xlnx_r5_remoteproc.c
@@ -1007,7 +1007,7 @@ static int zynqmp_r5_get_sram_banks(struct zynqmp_r5_core *r5_core)
}
/* Get SRAM device address */
- ret = of_property_read_reg(sram_np, i, &abs_addr, &size);
+ ret = of_property_read_reg(sram_np, 0, &abs_addr, &size);
if (ret) {
dev_err(dev, "failed to get reg property\n");
goto fail_sram_get;
diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 0666be6b0e88..fd4f107bd00e 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -148,11 +148,17 @@ static void mpam_free_garbage(void)
/*
* Once mpam is enabled, new requestors cannot further reduce the available
* partid. Assert that the size is fixed, and new requestors will be turned
- * away.
+ * away. This is needed when walking over structures sized by PARTID.
+ *
+ * During mpam_disable() these structures are not fixed, but the MSC state
+ * is still reset using whatever sizes have been discovered so far. As only
+ * PARTID 0 will be used after mpam_disable(), any race would be benign.
+ * Skip the check if a mpam_disable_reason has been set.
*/
static void mpam_assert_partid_sizes_fixed(void)
{
- WARN_ON_ONCE(!partid_max_published);
+ if (!mpam_disable_reason)
+ WARN_ON_ONCE(!partid_max_published);
}
static u32 __mpam_read_reg(struct mpam_msc *msc, u16 reg)
@@ -632,10 +638,9 @@ static struct mpam_msc_ris *mpam_get_or_create_ris(struct mpam_msc *msc,
* Try and see what values stick in this bit. If we can write either value,
* its probably not implemented by hardware.
*/
-static bool _mpam_ris_hw_probe_hw_nrdy(struct mpam_msc_ris *ris, u32 mon_reg)
+static bool mpam_ris_hw_probe_csu_nrdy(struct mpam_msc_ris *ris)
{
- u32 now;
- u64 mon_sel;
+ u32 now, mon_sel, ctl_val;
bool can_set, can_clear;
struct mpam_msc *msc = ris->vmsc->msc;
@@ -644,23 +649,30 @@ static bool _mpam_ris_hw_probe_hw_nrdy(struct mpam_msc_ris *ris, u32 mon_reg)
mon_sel = FIELD_PREP(MSMON_CFG_MON_SEL_MON_SEL, 0) |
FIELD_PREP(MSMON_CFG_MON_SEL_RIS, ris->ris_idx);
- _mpam_write_monsel_reg(msc, mon_reg, mon_sel);
+ mpam_write_monsel_reg(msc, CFG_MON_SEL, mon_sel);
+
+ /* Hardware might ignore nrdy if it's not enabled */
+ ctl_val = MSMON_CFG_CSU_CTL_TYPE_CSU;
+ ctl_val |= MSMON_CFG_x_CTL_MATCH_PARTID;
+ ctl_val |= MSMON_CFG_x_CTL_MATCH_PMG;
+ ctl_val |= MSMON_CFG_x_CTL_EN;
+ mpam_write_monsel_reg(msc, CFG_CSU_FLT, 0);
+ mpam_write_monsel_reg(msc, CFG_CSU_CTL, ctl_val);
- _mpam_write_monsel_reg(msc, mon_reg, MSMON___NRDY);
- now = _mpam_read_monsel_reg(msc, mon_reg);
+ _mpam_write_monsel_reg(msc, MSMON_CSU, MSMON___NRDY);
+ now = _mpam_read_monsel_reg(msc, MSMON_CSU);
can_set = now & MSMON___NRDY;
- _mpam_write_monsel_reg(msc, mon_reg, 0);
- now = _mpam_read_monsel_reg(msc, mon_reg);
+ _mpam_write_monsel_reg(msc, MSMON_CSU, 0);
+ /* Configuration change to try and coax hardware into setting nrdy */
+ mpam_write_monsel_reg(msc, CFG_CSU_FLT, 0x1);
+ now = _mpam_read_monsel_reg(msc, MSMON_CSU);
can_clear = !(now & MSMON___NRDY);
mpam_mon_sel_unlock(msc);
return (!can_set || !can_clear);
}
-#define mpam_ris_hw_probe_hw_nrdy(_ris, _mon_reg) \
- _mpam_ris_hw_probe_hw_nrdy(_ris, MSMON_##_mon_reg)
-
static void mpam_ris_hw_probe(struct mpam_msc_ris *ris)
{
int err;
@@ -770,20 +782,18 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris)
mpam_set_feature(mpam_feat_msmon_csu_xcl, props);
/* Is NRDY hardware managed? */
- hw_managed = mpam_ris_hw_probe_hw_nrdy(ris, CSU);
- if (hw_managed)
- mpam_set_feature(mpam_feat_msmon_csu_hw_nrdy, props);
- }
+ hw_managed = mpam_ris_hw_probe_csu_nrdy(ris);
- /*
- * Accept the missing firmware property if NRDY appears
- * un-implemented.
- */
- if (err && mpam_has_feature(mpam_feat_msmon_csu_hw_nrdy, props))
- dev_err_once(dev, "Counters are not usable because not-ready timeout was not provided by firmware.");
+ /*
+ * Accept the missing firmware property if NRDY appears
+ * un-implemented.
+ */
+ if (err && hw_managed)
+ dev_err_once(dev, "Counters are not usable because not-ready timeout was not provided by firmware.");
+ }
}
if (FIELD_GET(MPAMF_MSMON_IDR_MSMON_MBWU, msmon_features)) {
- bool has_long, hw_managed;
+ bool has_long;
u32 mbwumon_idr = mpam_read_partsel_reg(msc, MBWUMON_IDR);
props->num_mbwu_mon = FIELD_GET(MPAMF_MBWUMON_IDR_NUM_MON, mbwumon_idr);
@@ -802,16 +812,6 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris)
} else {
mpam_set_feature(mpam_feat_msmon_mbwu_31counter, props);
}
-
- /* Is NRDY hardware managed? */
- hw_managed = mpam_ris_hw_probe_hw_nrdy(ris, MBWU);
- if (hw_managed)
- mpam_set_feature(mpam_feat_msmon_mbwu_hw_nrdy, props);
-
- /*
- * Don't warn about any missing firmware property for
- * MBWU NRDY - it doesn't make any sense!
- */
}
}
}
@@ -1078,7 +1078,6 @@ static void __ris_msmon_read(void *arg)
bool reset_on_next_read = false;
struct mpam_msc_ris *ris = m->ris;
struct msmon_mbwu_state *mbwu_state;
- struct mpam_props *rprops = &ris->props;
struct mpam_msc *msc = m->ris->vmsc->msc;
u32 mon_sel, ctl_val, flt_val, cur_ctl, cur_flt;
@@ -1134,8 +1133,7 @@ static void __ris_msmon_read(void *arg)
switch (m->type) {
case mpam_feat_msmon_csu:
now = mpam_read_monsel_reg(msc, CSU);
- if (mpam_has_feature(mpam_feat_msmon_csu_hw_nrdy, rprops))
- nrdy = now & MSMON___NRDY;
+ nrdy = now & MSMON___NRDY;
now = FIELD_GET(MSMON___VALUE, now);
break;
case mpam_feat_msmon_mbwu_31counter:
@@ -1143,8 +1141,7 @@ static void __ris_msmon_read(void *arg)
case mpam_feat_msmon_mbwu_63counter:
if (m->type != mpam_feat_msmon_mbwu_31counter) {
now = mpam_msc_read_mbwu_l(msc);
- if (mpam_has_feature(mpam_feat_msmon_mbwu_hw_nrdy, rprops))
- nrdy = now & MSMON___L_NRDY;
+ nrdy = now & MSMON___L_NRDY;
if (m->type == mpam_feat_msmon_mbwu_63counter)
now = FIELD_GET(MSMON___LWD_VALUE, now);
@@ -1152,8 +1149,7 @@ static void __ris_msmon_read(void *arg)
now = FIELD_GET(MSMON___L_VALUE, now);
} else {
now = mpam_read_monsel_reg(msc, MBWU);
- if (mpam_has_feature(mpam_feat_msmon_mbwu_hw_nrdy, rprops))
- nrdy = now & MSMON___NRDY;
+ nrdy = now & MSMON___NRDY;
now = FIELD_GET(MSMON___VALUE, now);
}
@@ -1364,17 +1360,15 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
__mpam_intpart_sel(ris->ris_idx, partid, msc);
}
- if (mpam_has_feature(mpam_feat_cpor_part, rprops) &&
- mpam_has_feature(mpam_feat_cpor_part, cfg)) {
- if (cfg->reset_cpbm)
- mpam_reset_msc_bitmap(msc, MPAMCFG_CPBM, rprops->cpbm_wd);
- else
+ if (mpam_has_feature(mpam_feat_cpor_part, rprops)) {
+ if (mpam_has_feature(mpam_feat_cpor_part, cfg))
mpam_write_partsel_reg(msc, CPBM, cfg->cpbm);
+ else
+ mpam_reset_msc_bitmap(msc, MPAMCFG_CPBM, rprops->cpbm_wd);
}
- if (mpam_has_feature(mpam_feat_mbw_part, rprops) &&
- mpam_has_feature(mpam_feat_mbw_part, cfg)) {
- if (cfg->reset_mbw_pbm)
+ if (mpam_has_feature(mpam_feat_mbw_part, rprops)) {
+ if (mpam_has_feature(mpam_feat_mbw_part, cfg))
mpam_reset_msc_bitmap(msc, MPAMCFG_MBW_PBM, rprops->mbw_pbm_bits);
else
mpam_write_partsel_reg(msc, MBW_PBM, cfg->mbw_pbm);
@@ -1384,16 +1378,14 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
mpam_has_feature(mpam_feat_mbw_min, cfg))
mpam_write_partsel_reg(msc, MBW_MIN, 0);
- if (mpam_has_feature(mpam_feat_mbw_max, rprops) &&
- mpam_has_feature(mpam_feat_mbw_max, cfg)) {
- if (cfg->reset_mbw_max)
- mpam_write_partsel_reg(msc, MBW_MAX, MPAMCFG_MBW_MAX_MAX);
- else
+ if (mpam_has_feature(mpam_feat_mbw_max, rprops)) {
+ if (mpam_has_feature(mpam_feat_mbw_max, cfg))
mpam_write_partsel_reg(msc, MBW_MAX, cfg->mbw_max);
+ else
+ mpam_write_partsel_reg(msc, MBW_MAX, MPAMCFG_MBW_MAX_MAX);
}
- if (mpam_has_feature(mpam_feat_mbw_prop, rprops) &&
- mpam_has_feature(mpam_feat_mbw_prop, cfg))
+ if (mpam_has_feature(mpam_feat_mbw_prop, rprops))
mpam_write_partsel_reg(msc, MBW_PROP, 0);
if (mpam_has_feature(mpam_feat_cmax_cmax, rprops))
@@ -1493,16 +1485,6 @@ static int mpam_save_mbwu_state(void *arg)
return 0;
}
-static void mpam_init_reset_cfg(struct mpam_config *reset_cfg)
-{
- *reset_cfg = (struct mpam_config) {
- .reset_cpbm = true,
- .reset_mbw_pbm = true,
- .reset_mbw_max = true,
- };
- bitmap_fill(reset_cfg->features, MPAM_FEATURE_LAST);
-}
-
/*
* Called via smp_call_on_cpu() to prevent migration, while still being
* pre-emptible. Caller must hold mpam_srcu.
@@ -1510,14 +1492,12 @@ static void mpam_init_reset_cfg(struct mpam_config *reset_cfg)
static int mpam_reset_ris(void *arg)
{
u16 partid, partid_max;
- struct mpam_config reset_cfg;
+ struct mpam_config reset_cfg = {};
struct mpam_msc_ris *ris = arg;
if (ris->in_reset_state)
return 0;
- mpam_init_reset_cfg(&reset_cfg);
-
spin_lock(&partid_max_lock);
partid_max = mpam_partid_max;
spin_unlock(&partid_max_lock);
@@ -2379,6 +2359,9 @@ static void __destroy_component_cfg(struct mpam_component *comp)
lockdep_assert_held(&mpam_list_lock);
+ if (!comp->cfg)
+ return;
+
add_to_garbage(comp->cfg);
list_for_each_entry(vmsc, &comp->vmsc, comp_list) {
msc = vmsc->msc;
@@ -2694,6 +2677,7 @@ int mpam_apply_config(struct mpam_component *comp, u16 partid,
srcu_read_lock_held(&mpam_srcu)) {
arg.ris = ris;
mpam_touch_msc(msc, __write_config, &arg);
+ ris->in_reset_state = false;
}
mutex_unlock(&msc->cfg_lock);
}
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index e8971842b124..5f1fca64ce8b 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -167,14 +167,12 @@ enum mpam_device_features {
mpam_feat_msmon_csu,
mpam_feat_msmon_csu_capture,
mpam_feat_msmon_csu_xcl,
- mpam_feat_msmon_csu_hw_nrdy,
mpam_feat_msmon_mbwu,
mpam_feat_msmon_mbwu_31counter,
mpam_feat_msmon_mbwu_44counter,
mpam_feat_msmon_mbwu_63counter,
mpam_feat_msmon_mbwu_capture,
mpam_feat_msmon_mbwu_rwbw,
- mpam_feat_msmon_mbwu_hw_nrdy,
mpam_feat_partid_nrw,
MPAM_FEATURE_LAST
};
@@ -266,10 +264,6 @@ struct mpam_config {
u32 mbw_pbm;
u16 mbw_max;
- bool reset_cpbm;
- bool reset_mbw_pbm;
- bool reset_mbw_max;
-
struct mpam_garbage garbage;
};
diff --git a/drivers/reset/amlogic/reset-meson.c b/drivers/reset/amlogic/reset-meson.c
index 84610365a823..c303e8590dd6 100644
--- a/drivers/reset/amlogic/reset-meson.c
+++ b/drivers/reset/amlogic/reset-meson.c
@@ -42,6 +42,7 @@ static const struct meson_reset_param meson_s4_param = {
};
static const struct meson_reset_param t7_param = {
+ .reset_ops = &meson_reset_ops,
.reset_num = 224,
.reset_offset = 0x0,
.level_offset = 0x40,
diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c
index 3fee27914ba8..5f3a3e60a19d 100644
--- a/drivers/rtc/rtc-abx80x.c
+++ b/drivers/rtc/rtc-abx80x.c
@@ -933,6 +933,8 @@ static int abx80x_probe(struct i2c_client *client)
client->irq = 0;
}
}
+ if (client->irq <= 0)
+ clear_bit(RTC_FEATURE_ALARM, priv->rtc->features);
err = rtc_add_group(priv->rtc, &rtc_calib_attr_group);
if (err) {
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 08a5e9380e75..bad142c536e1 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -103,11 +103,6 @@ struct subchannel {
struct work_struct todo_work;
struct schib_config config;
u64 dma_mask;
- /*
- * Driver name to force a match. Do not set directly, because core
- * frees it. Use driver_set_override() to set or clear it.
- */
- const char *driver_override;
} __attribute__ ((aligned(8)));
DECLARE_PER_CPU_ALIGNED(struct irb, cio_irb);
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 5ab239f38588..e5a0ec6b4e3e 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -159,7 +159,6 @@ static void css_subchannel_release(struct device *dev)
sch->config.intparm = 0;
cio_commit_config(sch);
- kfree(sch->driver_override);
kfree(sch);
}
@@ -323,37 +322,9 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR_RO(modalias);
-static ssize_t driver_override_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct subchannel *sch = to_subchannel(dev);
- int ret;
-
- ret = driver_set_override(dev, &sch->driver_override, buf, count);
- if (ret)
- return ret;
-
- return count;
-}
-
-static ssize_t driver_override_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct subchannel *sch = to_subchannel(dev);
- ssize_t len;
-
- device_lock(dev);
- len = sysfs_emit(buf, "%s\n", sch->driver_override);
- device_unlock(dev);
- return len;
-}
-static DEVICE_ATTR_RW(driver_override);
-
static struct attribute *subch_attrs[] = {
&dev_attr_type.attr,
&dev_attr_modalias.attr,
- &dev_attr_driver_override.attr,
NULL,
};
@@ -1356,9 +1327,11 @@ static int css_bus_match(struct device *dev, const struct device_driver *drv)
struct subchannel *sch = to_subchannel(dev);
const struct css_driver *driver = to_cssdriver(drv);
struct css_device_id *id;
+ int ret;
/* When driver_override is set, only bind to the matching driver */
- if (sch->driver_override && strcmp(sch->driver_override, drv->name))
+ ret = device_match_driver_override(dev, drv);
+ if (ret == 0)
return 0;
for (id = driver->subchannel_type; id->match_flags; id++) {
@@ -1415,6 +1388,7 @@ static int css_uevent(const struct device *dev, struct kobj_uevent_env *env)
static const struct bus_type css_bus_type = {
.name = "css",
+ .driver_override = true,
.match = css_bus_match,
.probe = css_probe,
.remove = css_remove,
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index d652df96a507..f24e27add721 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -859,25 +859,24 @@ static int __ap_queue_devices_with_id_unregister(struct device *dev, void *data)
static int __ap_revise_reserved(struct device *dev, void *dummy)
{
- int rc, card, queue, devres, drvres;
+ int rc, card, queue, devres, drvres, ovrd;
if (is_queue_dev(dev)) {
struct ap_driver *ap_drv = to_ap_drv(dev->driver);
struct ap_queue *aq = to_ap_queue(dev);
- struct ap_device *ap_dev = &aq->ap_dev;
card = AP_QID_CARD(aq->qid);
queue = AP_QID_QUEUE(aq->qid);
- if (ap_dev->driver_override) {
- if (strcmp(ap_dev->driver_override,
- ap_drv->driver.name)) {
- pr_debug("reprobing queue=%02x.%04x\n", card, queue);
- rc = device_reprobe(dev);
- if (rc) {
- AP_DBF_WARN("%s reprobing queue=%02x.%04x failed\n",
- __func__, card, queue);
- }
+ ovrd = device_match_driver_override(dev, &ap_drv->driver);
+ if (ovrd > 0) {
+ /* override set and matches, nothing to do */
+ } else if (ovrd == 0) {
+ pr_debug("reprobing queue=%02x.%04x\n", card, queue);
+ rc = device_reprobe(dev);
+ if (rc) {
+ AP_DBF_WARN("%s reprobing queue=%02x.%04x failed\n",
+ __func__, card, queue);
}
} else {
mutex_lock(&ap_attr_mutex);
@@ -928,7 +927,7 @@ int ap_owned_by_def_drv(int card, int queue)
if (aq) {
const struct device_driver *drv = aq->ap_dev.device.driver;
const struct ap_driver *ap_drv = to_ap_drv(drv);
- bool override = !!aq->ap_dev.driver_override;
+ bool override = device_has_driver_override(&aq->ap_dev.device);
if (override && drv && ap_drv->flags & AP_DRIVER_FLAG_DEFAULT)
rc = 1;
@@ -977,7 +976,7 @@ static int ap_device_probe(struct device *dev)
{
struct ap_device *ap_dev = to_ap_dev(dev);
struct ap_driver *ap_drv = to_ap_drv(dev->driver);
- int card, queue, devres, drvres, rc = -ENODEV;
+ int card, queue, devres, drvres, rc = -ENODEV, ovrd;
if (!get_device(dev))
return rc;
@@ -991,10 +990,11 @@ static int ap_device_probe(struct device *dev)
*/
card = AP_QID_CARD(to_ap_queue(dev)->qid);
queue = AP_QID_QUEUE(to_ap_queue(dev)->qid);
- if (ap_dev->driver_override) {
- if (strcmp(ap_dev->driver_override,
- ap_drv->driver.name))
- goto out;
+ ovrd = device_match_driver_override(dev, &ap_drv->driver);
+ if (ovrd > 0) {
+ /* override set and matches, nothing to do */
+ } else if (ovrd == 0) {
+ goto out;
} else {
mutex_lock(&ap_attr_mutex);
devres = test_bit_inv(card, ap_perms.apm) &&
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index 51e08f27bd75..04ea256ecf91 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -166,7 +166,6 @@ void ap_driver_unregister(struct ap_driver *);
struct ap_device {
struct device device;
int device_type; /* AP device type. */
- const char *driver_override;
};
#define to_ap_dev(x) container_of((x), struct ap_device, device)
diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c
index 3fe2e41c5c6b..ca9819e6f7e7 100644
--- a/drivers/s390/crypto/ap_queue.c
+++ b/drivers/s390/crypto/ap_queue.c
@@ -734,26 +734,14 @@ static ssize_t driver_override_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct ap_queue *aq = to_ap_queue(dev);
- struct ap_device *ap_dev = &aq->ap_dev;
- int rc;
-
- device_lock(dev);
- if (ap_dev->driver_override)
- rc = sysfs_emit(buf, "%s\n", ap_dev->driver_override);
- else
- rc = sysfs_emit(buf, "\n");
- device_unlock(dev);
-
- return rc;
+ guard(spinlock)(&dev->driver_override.lock);
+ return sysfs_emit(buf, "%s\n", dev->driver_override.name ?: "");
}
static ssize_t driver_override_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct ap_queue *aq = to_ap_queue(dev);
- struct ap_device *ap_dev = &aq->ap_dev;
int rc = -EINVAL;
bool old_value;
@@ -764,13 +752,13 @@ static ssize_t driver_override_store(struct device *dev,
if (ap_apmask_aqmask_in_use)
goto out;
- old_value = ap_dev->driver_override ? true : false;
- rc = driver_set_override(dev, &ap_dev->driver_override, buf, count);
+ old_value = device_has_driver_override(dev);
+ rc = __device_set_driver_override(dev, buf, count);
if (rc)
goto out;
- if (old_value && !ap_dev->driver_override)
+ if (old_value && !device_has_driver_override(dev))
--ap_driver_override_ctr;
- else if (!old_value && ap_dev->driver_override)
+ else if (!old_value && device_has_driver_override(dev))
++ap_driver_override_ctr;
rc = count;
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 99b0750850b2..f6bfe75dd696 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -164,7 +164,7 @@ struct bmic_controller_parameters {
struct ctlr_info {
unsigned int *reply_map;
int ctlr;
- char devname[8];
+ char devname[16];
char *product_name;
struct pci_dev *pdev;
u32 board_id;
@@ -255,7 +255,7 @@ struct ctlr_info {
int remove_in_progress;
/* Address of h->q[x] is passed to intr handler to know which queue */
u8 q[MAX_REPLY_QUEUES];
- char intrname[MAX_REPLY_QUEUES][16]; /* "hpsa0-msix00" names */
+ char intrname[MAX_REPLY_QUEUES][32]; /* controller and IRQ names */
u32 TMFSupportFlags; /* cache what task mgmt funcs are supported. */
#define HPSATMF_BITS_SUPPORTED (1 << 0)
#define HPSATMF_PHYS_LUN_RESET (1 << 1)
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 2e584a8bf66b..6a05ce195aa0 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -1638,7 +1638,7 @@ qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr,
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
int rval = QLA_FUNCTION_FAILED;
- uint16_t state[6];
+ uint16_t state[16];
uint32_t pstate;
if (IS_QLAFX00(vha->hw)) {
@@ -2402,6 +2402,63 @@ qla2x00_dport_diagnostics_show(struct device *dev,
vha->dport_data[0], vha->dport_data[1],
vha->dport_data[2], vha->dport_data[3]);
}
+
+static ssize_t
+qla2x00_mpi_fw_state_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int rval = QLA_FUNCTION_FAILED;
+ u16 state[16];
+ u16 mpi_state;
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!(IS_QLA27XX(ha) || IS_QLA28XX(ha)))
+ return scnprintf(buf, PAGE_SIZE,
+ "MPI state reporting is not supported for this HBA.\n");
+
+ memset(state, 0, sizeof(state));
+
+ mutex_lock(&vha->hw->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&vha->hw->optrom_mutex);
+ ql_dbg(ql_dbg_user, vha, 0x70df,
+ "ISP reset is in progress, failing mpi_fw_state.\n");
+ return -EBUSY;
+ } else if (vha->hw->flags.eeh_busy) {
+ mutex_unlock(&vha->hw->optrom_mutex);
+ ql_dbg(ql_dbg_user, vha, 0x70ea,
+ "HBA in PCI error state, failing mpi_fw_state.\n");
+ return -EBUSY;
+ }
+
+ rval = qla2x00_get_firmware_state(vha, state);
+ mutex_unlock(&vha->hw->optrom_mutex);
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_user, vha, 0x70eb,
+ "MB Command to retrieve MPI state failed (%d), failing mpi_fw_state.\n",
+ rval);
+ return -EIO;
+ }
+
+ mpi_state = state[11];
+
+ if (!(mpi_state & BIT_15))
+ return scnprintf(buf, PAGE_SIZE,
+ "MPI firmware state reporting is not supported by this firmware. (0x%02x)\n",
+ mpi_state);
+
+ if (!(mpi_state & BIT_8))
+ return scnprintf(buf, PAGE_SIZE,
+ "MPI firmware is disabled. (0x%02x)\n",
+ mpi_state);
+
+ return scnprintf(buf, PAGE_SIZE,
+ "MPI firmware is enabled, state is %s. (0x%02x)\n",
+ mpi_state & BIT_9 ? "active" : "inactive",
+ mpi_state);
+}
+
static DEVICE_ATTR(dport_diagnostics, 0444,
qla2x00_dport_diagnostics_show, NULL);
@@ -2469,6 +2526,8 @@ static DEVICE_ATTR(port_speed, 0644, qla2x00_port_speed_show,
qla2x00_port_speed_store);
static DEVICE_ATTR(port_no, 0444, qla2x00_port_no_show, NULL);
static DEVICE_ATTR(fw_attr, 0444, qla2x00_fw_attr_show, NULL);
+static DEVICE_ATTR(mpi_fw_state, 0444, qla2x00_mpi_fw_state_show, NULL);
+
static struct attribute *qla2x00_host_attrs[] = {
&dev_attr_driver_version.attr.attr,
@@ -2517,6 +2576,7 @@ static struct attribute *qla2x00_host_attrs[] = {
&dev_attr_qlini_mode.attr,
&dev_attr_ql2xiniexchg.attr,
&dev_attr_ql2xexchoffld.attr,
+ &dev_attr_mpi_fw_state.attr,
NULL,
};
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 730c42b1a7b9..e746c9274cde 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -4914,7 +4914,7 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
unsigned long wtime, mtime, cs84xx_time;
uint16_t min_wait; /* Minimum wait time if loop is down */
uint16_t wait_time; /* Wait time if loop is coming ready */
- uint16_t state[6];
+ uint16_t state[16];
struct qla_hw_data *ha = vha->hw;
if (IS_QLAFX00(vha->hw))
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 0d598be6f3ea..44e310f1a370 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -2268,6 +2268,13 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
else
mcp->in_mb = MBX_1|MBX_0;
+
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+ mcp->mb[12] = 0;
+ mcp->out_mb |= MBX_12;
+ mcp->in_mb |= MBX_12;
+ }
+
mcp->tov = MBX_TOV_SECONDS;
mcp->flags = 0;
rval = qla2x00_mailbox_command(vha, mcp);
@@ -2280,6 +2287,8 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
states[3] = mcp->mb[4];
states[4] = mcp->mb[5];
states[5] = mcp->mb[6]; /* DPORT status */
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
+ states[11] = mcp->mb[12]; /* MPI state. */
}
if (rval != QLA_SUCCESS) {
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 37bac49f30f0..f38d36fbeef3 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1623,10 +1623,35 @@ sg_remove_device(struct device *cl_dev)
}
module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR);
-module_param_named(def_reserved_size, def_reserved_size, int,
- S_IRUGO | S_IWUSR);
module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR);
+static int def_reserved_size_set(const char *val, const struct kernel_param *kp)
+{
+ int size, ret;
+
+ if (!val)
+ return -EINVAL;
+
+ ret = kstrtoint(val, 0, &size);
+ if (ret)
+ return ret;
+
+ /* limit to 1 MB */
+ if (size < 0 || size > 1048576)
+ return -ERANGE;
+
+ def_reserved_size = size;
+ return 0;
+}
+
+static const struct kernel_param_ops def_reserved_size_ops = {
+ .set = def_reserved_size_set,
+ .get = param_get_int,
+};
+
+module_param_cb(def_reserved_size, &def_reserved_size_ops, &def_reserved_size,
+ S_IRUGO | S_IWUSR);
+
MODULE_AUTHOR("Douglas Gilbert");
MODULE_DESCRIPTION("SCSI generic (sg) driver");
MODULE_LICENSE("GPL");
@@ -1691,13 +1716,13 @@ init_sg(void)
sg_sysfs_valid = 1;
rc = scsi_register_interface(&sg_interface);
if (0 == rc) {
+ register_sg_sysctls();
#ifdef CONFIG_SCSI_PROC_FS
sg_proc_init();
#endif /* CONFIG_SCSI_PROC_FS */
return 0;
}
class_unregister(&sg_sysfs_class);
- register_sg_sysctls();
err_out:
unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS);
return rc;
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 7adb2573f50d..c36c54ecd354 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -395,7 +395,7 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt)
switch (req_op(rq)) {
case REQ_OP_WRITE:
- if (!cd->writeable)
+ if (get_disk_ro(cd->disk))
goto out;
SCpnt->cmnd[0] = WRITE_10;
cd->cdi.media_written = 1;
@@ -681,6 +681,7 @@ static int sr_probe(struct scsi_device *sdev)
error = -ENOMEM;
if (get_capabilities(cd))
goto fail_minor;
+ cdrom_probe_write_features(&cd->cdi);
sr_vendor_init(cd);
set_capacity(disk, cd->capacity);
@@ -899,14 +900,6 @@ static int get_capabilities(struct scsi_cd *cd)
/*else I don't think it can close its tray
cd->cdi.mask |= CDC_CLOSE_TRAY; */
- /*
- * if DVD-RAM, MRW-W or CD-RW, we are randomly writable
- */
- if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) !=
- (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) {
- cd->writeable = 1;
- }
-
kfree(buffer);
return 0;
}
diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h
index dc899277b3a4..2d92f9cb6fec 100644
--- a/drivers/scsi/sr.h
+++ b/drivers/scsi/sr.h
@@ -35,7 +35,6 @@ typedef struct scsi_cd {
struct scsi_device *device;
unsigned int vendor; /* vendor code, see sr_vendor.c */
unsigned long ms_offset; /* for reading multisession-CD's */
- unsigned writeable : 1;
unsigned use:1; /* is this device still supportable */
unsigned xa_flag:1; /* CD has XA sectors ? */
unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */
diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c
index ad5899d083f3..b80d3f9cff64 100644
--- a/drivers/soc/qcom/llcc-qcom.c
+++ b/drivers/soc/qcom/llcc-qcom.c
@@ -3943,7 +3943,7 @@ static const struct llcc_slice_config x1e80100_data[] = {
static const struct llcc_edac_reg_offset llcc_v1_edac_reg_offset = {
.trp_ecc_error_status0 = 0x20344,
.trp_ecc_error_status1 = 0x20348,
- .trp_ecc_sb_err_syn0 = 0x2304c,
+ .trp_ecc_sb_err_syn0 = 0x2034c,
.trp_ecc_db_err_syn0 = 0x20370,
.trp_ecc_error_cntr_clear = 0x20440,
.trp_interrupt_0_status = 0x20480,
diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c
index 6a23f18b0281..96ca0b87bfc4 100644
--- a/drivers/soc/qcom/ocmem.c
+++ b/drivers/soc/qcom/ocmem.c
@@ -196,17 +196,16 @@ struct ocmem *of_get_ocmem(struct device *dev)
}
pdev = of_find_device_by_node(devnode->parent);
- if (!pdev) {
- dev_err(dev, "Cannot find device node %s\n", devnode->name);
- return ERR_PTR(-EPROBE_DEFER);
- }
+ if (!pdev)
+ return dev_err_ptr_probe(dev, -EPROBE_DEFER,
+ "Cannot find device node %s\n",
+ devnode->name);
ocmem = platform_get_drvdata(pdev);
put_device(&pdev->dev);
- if (!ocmem) {
- dev_err(dev, "Cannot get ocmem\n");
- return ERR_PTR(-ENODEV);
- }
+ if (!ocmem)
+ return dev_err_ptr_probe(dev, -EPROBE_DEFER, "Cannot get ocmem\n");
+
return ocmem;
}
EXPORT_SYMBOL_GPL(of_get_ocmem);
@@ -308,7 +307,7 @@ static int ocmem_dev_probe(struct platform_device *pdev)
ocmem->dev = dev;
ocmem->config = device_get_match_data(dev);
- ocmem->core_clk = devm_clk_get(dev, "core");
+ ocmem->core_clk = devm_clk_get_optional(dev, "core");
if (IS_ERR(ocmem->core_clk))
return dev_err_probe(dev, PTR_ERR(ocmem->core_clk),
"Unable to get core clock\n");
diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c
index a543ab9bee6c..c255662b8fc3 100644
--- a/drivers/soc/qcom/qcom_aoss.c
+++ b/drivers/soc/qcom/qcom_aoss.c
@@ -355,7 +355,7 @@ static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev,
/* Normalize state */
cdev_state = !!state;
- if (qmp_cdev->state == state)
+ if (qmp_cdev->state == cdev_state)
return 0;
ret = qmp_send(qmp_cdev->qmp, "{class: volt_flr, event:zero_temp, res:%s, value:%s}",
diff --git a/drivers/soc/qcom/ubwc_config.c b/drivers/soc/qcom/ubwc_config.c
index 1c25aaf55e52..8304463f238a 100644
--- a/drivers/soc/qcom/ubwc_config.c
+++ b/drivers/soc/qcom/ubwc_config.c
@@ -231,8 +231,7 @@ static const struct qcom_ubwc_cfg_data x1e80100_data = {
static const struct qcom_ubwc_cfg_data glymur_data = {
.ubwc_enc_version = UBWC_5_0,
.ubwc_dec_version = UBWC_5_0,
- .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
- UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_swizzle = 0,
.ubwc_bank_spread = true,
/* TODO: highest_bank_bit = 15 for LP_DDR4 */
.highest_bank_bit = 16,
diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c
index a9adbcecd47c..7e387fc54c6b 100644
--- a/drivers/soc/tegra/cbb/tegra234-cbb.c
+++ b/drivers/soc/tegra/cbb/tegra234-cbb.c
@@ -313,12 +313,37 @@ static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *target
}
}
+static struct tegra234_cbb *tegra234_cbb_get_fabric(u8 fab_id)
+{
+ struct tegra_cbb *entry;
+
+ list_for_each_entry(entry, &cbb_list, node) {
+ struct tegra234_cbb *priv = to_tegra234_cbb(entry);
+
+ if (priv->fabric->fab_id == fab_id)
+ return priv;
+ }
+
+ return NULL;
+}
+
static void tegra234_sw_lookup_target_timeout(struct seq_file *file, struct tegra234_cbb *cbb,
u8 target_id, u8 fab_id)
{
const struct tegra234_target_lookup *map = cbb->fabric->fab_list[fab_id].target_map;
+ struct tegra234_cbb *target_cbb = NULL;
void __iomem *addr;
+ if (fab_id == cbb->fabric->fab_id)
+ target_cbb = cbb;
+ else
+ target_cbb = tegra234_cbb_get_fabric(fab_id);
+
+ if (!target_cbb) {
+ dev_err(cbb->base.dev, "could not find fabric for fab_id:%d\n", fab_id);
+ return;
+ }
+
if (target_id >= cbb->fabric->fab_list[fab_id].max_targets) {
tegra_cbb_print_err(file, "\t Invalid target_id:%d\n", target_id);
return;
@@ -341,7 +366,7 @@ static void tegra234_sw_lookup_target_timeout(struct seq_file *file, struct tegr
* e) Goto step-a till all bits are set.
*/
- addr = cbb->regs + map[target_id].offset;
+ addr = target_cbb->regs + map[target_id].offset;
if (strstr(map[target_id].name, "AXI2APB")) {
addr += APB_BLOCK_TMO_STATUS_0;
@@ -881,7 +906,7 @@ static const struct tegra234_fabric_lookup tegra234_cbb_fab_list[] = {
ARRAY_SIZE(tegra234_common_target_map) },
[T234_AON_FABRIC_ID] = { "aon-fabric", true,
tegra234_aon_target_map,
- ARRAY_SIZE(tegra234_bpmp_target_map) },
+ ARRAY_SIZE(tegra234_aon_target_map) },
[T234_PSC_FABRIC_ID] = { "psc-fabric" },
[T234_BPMP_FABRIC_ID] = { "bpmp-fabric", true,
tegra234_bpmp_target_map,
@@ -1160,7 +1185,7 @@ static const struct tegra234_fabric_lookup tegra241_cbb_fab_list[] = {
[T234_CBB_FABRIC_ID] = { "cbb-fabric", true,
tegra241_cbb_target_map, ARRAY_SIZE(tegra241_cbb_target_map) },
[T234_BPMP_FABRIC_ID] = { "bpmp-fabric", true,
- tegra241_bpmp_target_map, ARRAY_SIZE(tegra241_cbb_target_map) },
+ tegra241_bpmp_target_map, ARRAY_SIZE(tegra241_bpmp_target_map) },
};
static const struct tegra234_cbb_fabric tegra241_cbb_fabric = {
.fab_id = T234_CBB_FABRIC_ID,
@@ -1586,6 +1611,10 @@ static int __maybe_unused tegra234_cbb_resume_noirq(struct device *dev)
{
struct tegra234_cbb *cbb = dev_get_drvdata(dev);
+ /* set ERD bit to mask SError and generate interrupt to report error */
+ if (cbb->fabric->off_mask_erd)
+ tegra234_cbb_mask_serror(cbb);
+
tegra234_cbb_error_enable(&cbb->base);
dev_dbg(dev, "%s resumed\n", cbb->fabric->fab_list[cbb->fabric->fab_id].name);
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index a1a2966512d1..6debaabdaa36 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -437,7 +437,10 @@ struct tegra_pmc_soc {
* @wake_sw_status_map: Bitmap to hold raw status of wakes without mask
* @wake_cntrl_level_map: Bitmap to hold wake levels to be programmed in
* cntrl register associated with each wake during system suspend.
+ * @reboot_notifier: PMC reboot notifier handler
* @syscore: syscore suspend/resume callbacks
+ * @wake_work: IRQ work handler for processing wake-up events.
+ * @wake_status: Status of wake-up events.
*/
struct tegra_pmc {
struct device *dev;
@@ -1004,7 +1007,7 @@ static struct tegra_pmc *tegra_pmc_get(struct device *dev)
}
/**
- * tegra_pmc_get() - find the PMC for a given device
+ * devm_tegra_pmc_get() - find the PMC for a given device
* @dev: device for which to find the PMC
*
* Returns a pointer to the PMC on success or an ERR_PTR()-encoded error code
@@ -1746,7 +1749,7 @@ static void tegra_io_pad_unprepare(struct tegra_pmc *pmc)
}
/**
- * tegra_io_pad_power_enable() - enable power to I/O pad
+ * tegra_pmc_io_pad_power_enable() - enable power to I/O pad
* @pmc: power management controller
* @id: Tegra I/O pad ID for which to enable power
*
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index fb68738dfb9b..fe5316d93fef 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -1899,8 +1899,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
if (status[i] == SDW_SLAVE_UNATTACHED &&
slave->status != SDW_SLAVE_UNATTACHED) {
- dev_warn(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n",
- i, slave->status);
+ dev_dbg(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n",
+ i, slave->status);
sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED);
/* Ensure driver knows that peripheral unattached */
@@ -1951,8 +1951,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
if (slave->status == SDW_SLAVE_UNATTACHED)
break;
- dev_warn(&slave->dev, "Slave %d state check2: UNATTACHED, status was %d\n",
- i, slave->status);
+ dev_dbg(&slave->dev, "Slave %d state check2: UNATTACHED, status was %d\n",
+ i, slave->status);
sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED);
break;
diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index f245c3ffb9e9..b8b62735c893 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -933,6 +933,14 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
cdns_read_response(cdns);
+ /*
+ * Clear interrupt before signalling the completion to avoid
+ * a race between this thread and the main thread starting
+ * another TX.
+ */
+ cdns_writel(cdns, CDNS_MCP_INTSTAT, CDNS_MCP_INT_RX_WL);
+ int_status &= ~CDNS_MCP_INT_RX_WL;
+
if (defer && defer->msg) {
cdns_fill_msg_resp(cdns, defer->msg,
defer->length, 0);
diff --git a/drivers/soundwire/debugfs.c b/drivers/soundwire/debugfs.c
index ccc9670ef77c..2905ec19b838 100644
--- a/drivers/soundwire/debugfs.c
+++ b/drivers/soundwire/debugfs.c
@@ -358,8 +358,8 @@ void sdw_slave_debugfs_init(struct sdw_slave *slave)
debugfs_create_file("go", 0200, d, slave, &cmd_go_fops);
debugfs_create_file("read_buffer", 0400, d, slave, &read_buffer_fops);
- firmware_file = NULL;
- debugfs_create_str("firmware_file", 0200, d, &firmware_file);
+ if (firmware_file)
+ debugfs_create_str("firmware_file", 0200, d, &firmware_file);
slave->debugfs = d;
}
@@ -371,10 +371,15 @@ void sdw_slave_debugfs_exit(struct sdw_slave *slave)
void sdw_debugfs_init(void)
{
+ if (!firmware_file)
+ firmware_file = kstrdup("", GFP_KERNEL);
+
sdw_debugfs_root = debugfs_create_dir("soundwire", NULL);
}
void sdw_debugfs_exit(void)
{
debugfs_remove_recursive(sdw_debugfs_root);
+ kfree(firmware_file);
+ firmware_file = NULL;
}
diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c
index 7f01e43ae978..20422534baf1 100644
--- a/drivers/soundwire/intel_ace2x.c
+++ b/drivers/soundwire/intel_ace2x.c
@@ -82,6 +82,11 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
int len;
int i;
+ if (cdns->bus.bpt_stream) {
+ dev_err(cdns->dev, "%s: BPT stream already exists\n", __func__);
+ return -EAGAIN;
+ }
+
stream = sdw_alloc_stream("BPT", SDW_STREAM_BPT);
if (!stream)
return -ENOMEM;
diff --git a/drivers/spi/spi-amlogic-spisg.c b/drivers/spi/spi-amlogic-spisg.c
index e15d7112bb55..0280868f7edf 100644
--- a/drivers/spi/spi-amlogic-spisg.c
+++ b/drivers/spi/spi-amlogic-spisg.c
@@ -794,6 +794,7 @@ static int aml_spisg_probe(struct platform_device *pdev)
dma_set_max_seg_size(&pdev->dev, SPISG_BLOCK_MAX);
+ init_completion(&spisg->completion);
ret = devm_request_irq(&pdev->dev, irq, aml_spisg_irq, 0, NULL, spisg);
if (ret) {
dev_err(&pdev->dev, "irq request failed\n");
@@ -806,8 +807,6 @@ static int aml_spisg_probe(struct platform_device *pdev)
goto out_clk;
}
- init_completion(&spisg->completion);
-
pm_runtime_put(&spisg->pdev->dev);
return 0;
diff --git a/drivers/spi/spi-atcspi200.c b/drivers/spi/spi-atcspi200.c
index 2665f31a49ce..02517af9e398 100644
--- a/drivers/spi/spi-atcspi200.c
+++ b/drivers/spi/spi-atcspi200.c
@@ -567,6 +567,8 @@ static int atcspi_probe(struct platform_device *pdev)
spi->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, host);
+ mutex_init(&spi->mutex_lock);
+
ret = atcspi_init_resources(pdev, spi, &mem_res);
if (ret)
goto free_controller;
@@ -597,7 +599,6 @@ static int atcspi_probe(struct platform_device *pdev)
else
spi->use_dma = true;
}
- mutex_init(&spi->mutex_lock);
return 0;
@@ -605,6 +606,7 @@ static int atcspi_probe(struct platform_device *pdev)
clk_disable_unprepare(spi->clk);
free_controller:
+ mutex_destroy(&spi->mutex_lock);
spi_controller_put(host);
return ret;
}
diff --git a/drivers/spi/spi-axiado.c b/drivers/spi/spi-axiado.c
index 8ddcd27def22..2cefc8917b71 100644
--- a/drivers/spi/spi-axiado.c
+++ b/drivers/spi/spi-axiado.c
@@ -201,7 +201,7 @@ static void ax_spi_fill_tx_fifo(struct ax_spi *xspi)
* then spi control did't work thoroughly, add one byte delay
*/
if (ax_spi_read(xspi, AX_SPI_IVR) & AX_SPI_IVR_TFOV)
- usleep_range(10, 10);
+ udelay(10);
if (xspi->tx_buf)
ax_spi_write_b(xspi, AX_SPI_TXFIFO, *xspi->tx_buf++);
else
@@ -842,7 +842,6 @@ static int ax_spi_probe(struct platform_device *pdev)
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
- pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
ctlr->mem_ops = &ax_spi_mem_ops;
diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
index 1b0d6186c7ef..057381e56a7f 100644
--- a/drivers/spi/spi-cadence-quadspi.c
+++ b/drivers/spi/spi-cadence-quadspi.c
@@ -1544,10 +1544,6 @@ static bool cqspi_supports_mem_op(struct spi_mem *mem,
if (op->data.nbytes && op->data.buswidth != 8)
return false;
- /* A single opcode is supported, it will be repeated */
- if ((op->cmd.opcode >> 8) != (op->cmd.opcode & 0xFF))
- return false;
-
if (cqspi->is_rzn1)
return false;
} else if (!all_false) {
diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c
index a223b4bc6e63..57358851029b 100644
--- a/drivers/spi/spi-fsl-qspi.c
+++ b/drivers/spi/spi-fsl-qspi.c
@@ -633,7 +633,7 @@ static int fsl_qspi_do_op(struct fsl_qspi *q, const struct spi_mem_op *op)
void __iomem *base = q->iobase;
int err = 0;
- init_completion(&q->c);
+ reinit_completion(&q->c);
/*
* Always start the sequence at the same index since we update
@@ -965,6 +965,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
+ init_completion(&q->c);
ret = devm_request_irq(dev, ret,
fsl_qspi_irq_handler, 0, pdev->name, q);
if (ret) {
diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c
index 216a0a91fc47..c42d2a2cdf1e 100644
--- a/drivers/spi/spi-hisi-kunpeng.c
+++ b/drivers/spi/spi-hisi-kunpeng.c
@@ -196,8 +196,18 @@ static void hisi_spi_flush_fifo(struct hisi_spi *hs)
unsigned long limit = loops_per_jiffy << 1;
do {
- while (hisi_spi_rx_not_empty(hs))
+ unsigned long inner_limit = loops_per_jiffy;
+
+ while (hisi_spi_rx_not_empty(hs) && --inner_limit) {
readl(hs->regs + HISI_SPI_DOUT);
+ cpu_relax();
+ }
+
+ if (!inner_limit) {
+ dev_warn_ratelimited(hs->dev, "RX FIFO flush timeout\n");
+ break;
+ }
+
} while (hisi_spi_busy(hs) && limit--);
}
diff --git a/drivers/spi/spi-mtk-snfi.c b/drivers/spi/spi-mtk-snfi.c
index 437edbd658aa..73fa84475f0e 100644
--- a/drivers/spi/spi-mtk-snfi.c
+++ b/drivers/spi/spi-mtk-snfi.c
@@ -1303,6 +1303,13 @@ static const struct spi_controller_mem_caps mtk_snand_mem_caps = {
.ecc = true,
};
+static void mtk_unregister_ecc_engine(void *data)
+{
+ struct nand_ecc_engine *eng = data;
+
+ nand_ecc_unregister_on_host_hw_engine(eng);
+}
+
static irqreturn_t mtk_snand_irq(int irq, void *id)
{
struct mtk_snand *snf = id;
@@ -1443,6 +1450,13 @@ static int mtk_snand_probe(struct platform_device *pdev)
goto release_ecc;
}
+ ret = devm_add_action_or_reset(&pdev->dev, mtk_unregister_ecc_engine,
+ &ms->ecc_eng);
+ if (ret) {
+ dev_err_probe(&pdev->dev, ret, "failed to add ECC unregister action\n");
+ goto release_ecc;
+ }
+
ctlr->num_chipselect = 1;
ctlr->mem_ops = &mtk_snand_mem_ops;
ctlr->mem_caps = &mtk_snand_mem_caps;
diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c
index 320b3d93df57..1e36ae084dd8 100644
--- a/drivers/spi/spi-nxp-fspi.c
+++ b/drivers/spi/spi-nxp-fspi.c
@@ -996,7 +996,7 @@ static int nxp_fspi_do_op(struct nxp_fspi *f, const struct spi_mem_op *op)
reg = reg | FSPI_IPRXFCR_CLR;
fspi_writel(f, reg, base + FSPI_IPRXFCR);
- init_completion(&f->c);
+ reinit_completion(&f->c);
fspi_writel(f, op->addr.val, base + FSPI_IPCR0);
/*
@@ -1365,6 +1365,7 @@ static int nxp_fspi_probe(struct platform_device *pdev)
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to disable clock");
+ init_completion(&f->c);
ret = devm_request_irq(dev, irq,
nxp_fspi_irq_handler, 0, pdev->name, f);
if (ret)
diff --git a/drivers/spi/spi-nxp-xspi.c b/drivers/spi/spi-nxp-xspi.c
index 06fcdf22990b..385302a6e62f 100644
--- a/drivers/spi/spi-nxp-xspi.c
+++ b/drivers/spi/spi-nxp-xspi.c
@@ -958,7 +958,7 @@ static int nxp_xspi_do_op(struct nxp_xspi *xspi, const struct spi_mem_op *op)
writel(reg, base + XSPI_RBCT);
}
- init_completion(&xspi->c);
+ reinit_completion(&xspi->c);
/* Config the data address */
writel(op->addr.val + xspi->memmap_phy, base + XSPI_SFP_TG_SFAR);
@@ -1273,6 +1273,7 @@ static int nxp_xspi_probe(struct platform_device *pdev)
nxp_xspi_default_setup(xspi);
+ init_completion(&xspi->c);
ret = devm_request_irq(dev, irq,
nxp_xspi_irq_handler, 0, pdev->name, xspi);
if (ret)
diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index eb1992b4178e..2eb9ede8cc90 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -357,7 +357,8 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id)
struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
/* When int_cs_inactive comes, spi target abort */
- if (rs->cs_inactive && readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) {
+ if (rs->cs_inactive &&
+ (readl_relaxed(rs->regs + ROCKCHIP_SPI_ISR) & INT_CS_INACTIVE)) {
ctlr->target_abort(ctlr);
writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR);
writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR);
diff --git a/drivers/spi/spi-rzv2h-rspi.c b/drivers/spi/spi-rzv2h-rspi.c
index 23f0e92ae208..53c44799fab7 100644
--- a/drivers/spi/spi-rzv2h-rspi.c
+++ b/drivers/spi/spi-rzv2h-rspi.c
@@ -50,7 +50,6 @@
/* Register SPBR */
#define RSPI_SPBR_SPR_MIN 0
-#define RSPI_SPBR_SPR_PCLK_MIN 1
#define RSPI_SPBR_SPR_MAX 255
/* Register SPCMD */
@@ -533,6 +532,17 @@ static void rzv2h_rspi_find_rate_fixed(struct clk *clk, u32 hz,
for (brdv = RSPI_SPCMD_BRDV_MIN; brdv <= RSPI_SPCMD_BRDV_MAX; brdv++) {
spr = DIV_ROUND_UP(clk_rate, hz * (1 << (brdv + 1)));
spr--;
+ /*
+ * Skip SPR=0 and BRDV=0 as it is not a valid combination:
+ * - On RZ/G3E, RZ/G3L, RZ/V2H(P) and RZ/V2N, RSPI_n_TCLK is
+ * fixed at 200MHz and SPR=0 and BRDV=0 results in the maximum
+ * bit rate of 100Mbps which is prohibited.
+ * - On RZ/T2H and RZ/N2H, when PCLK (125MHz) is used as
+ * the clock source, SPR=0 and BRDV=0 is explicitly listed
+ * as unsupported in the hardware manual (Table 36.7).
+ */
+ if (!spr && !brdv)
+ continue;
if (spr >= spr_min && spr <= spr_max)
goto clock_found;
}
@@ -566,16 +576,12 @@ static u32 rzv2h_rspi_setup_clock(struct rzv2h_rspi_priv *rspi, u32 hz)
rspi->info->find_tclk_rate(rspi->tclk, hz, RSPI_SPBR_SPR_MIN,
RSPI_SPBR_SPR_MAX, &best_clock);
- /*
- * T2H and N2H can also use PCLK as a source, which is 125MHz, but not
- * when both SPR and BRDV are 0.
- */
if (best_clock.error && rspi->info->find_pclk_rate)
- rspi->info->find_pclk_rate(rspi->pclk, hz, RSPI_SPBR_SPR_PCLK_MIN,
+ rspi->info->find_pclk_rate(rspi->pclk, hz, RSPI_SPBR_SPR_MIN,
RSPI_SPBR_SPR_MAX, &best_clock);
if (!best_clock.clk_rate)
- return -EINVAL;
+ return 0;
ret = clk_set_rate(best_clock.clk, best_clock.clk_rate);
if (ret)
diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c
index 6c7aba8befa0..74a3e32fd2b5 100644
--- a/drivers/spi/spi-sifive.c
+++ b/drivers/spi/spi-sifive.c
@@ -312,7 +312,8 @@ static int sifive_spi_probe(struct platform_device *pdev)
goto put_host;
}
- spi->clk = devm_clk_get(&pdev->dev, NULL);
+ /* Spin up the bus clock before hitting registers */
+ spi->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(spi->clk)) {
dev_err(&pdev->dev, "Unable to find bus clock\n");
ret = PTR_ERR(spi->clk);
@@ -342,13 +343,6 @@ static int sifive_spi_probe(struct platform_device *pdev)
goto put_host;
}
- /* Spin up the bus clock before hitting registers */
- ret = clk_prepare_enable(spi->clk);
- if (ret) {
- dev_err(&pdev->dev, "Unable to enable bus clock\n");
- goto put_host;
- }
-
/* probe the number of CS lines */
spi->cs_inactive = sifive_spi_read(spi, SIFIVE_SPI_REG_CSDEF);
sifive_spi_write(spi, SIFIVE_SPI_REG_CSDEF, 0xffffffffU);
@@ -357,14 +351,14 @@ static int sifive_spi_probe(struct platform_device *pdev)
if (!cs_bits) {
dev_err(&pdev->dev, "Could not auto probe CS lines\n");
ret = -EINVAL;
- goto disable_clk;
+ goto put_host;
}
num_cs = ilog2(cs_bits) + 1;
if (num_cs > SIFIVE_SPI_MAX_CS) {
dev_err(&pdev->dev, "Invalid number of spi targets\n");
ret = -EINVAL;
- goto disable_clk;
+ goto put_host;
}
/* Define our host */
@@ -392,22 +386,20 @@ static int sifive_spi_probe(struct platform_device *pdev)
dev_name(&pdev->dev), spi);
if (ret) {
dev_err(&pdev->dev, "Unable to bind to interrupt\n");
- goto disable_clk;
+ goto put_host;
}
dev_info(&pdev->dev, "mapped; irq=%d, cs=%d\n",
irq, host->num_chipselect);
- ret = devm_spi_register_controller(&pdev->dev, host);
+ ret = spi_register_controller(host);
if (ret < 0) {
dev_err(&pdev->dev, "spi_register_host failed\n");
- goto disable_clk;
+ goto put_host;
}
return 0;
-disable_clk:
- clk_disable_unprepare(spi->clk);
put_host:
spi_controller_put(host);
@@ -419,9 +411,14 @@ static void sifive_spi_remove(struct platform_device *pdev)
struct spi_controller *host = platform_get_drvdata(pdev);
struct sifive_spi *spi = spi_controller_get_devdata(host);
+ spi_controller_get(host);
+
+ spi_unregister_controller(host);
+
/* Disable all the interrupts just in case */
sifive_spi_write(spi, SIFIVE_SPI_REG_IE, 0);
- clk_disable_unprepare(spi->clk);
+
+ spi_controller_put(host);
}
static int sifive_spi_suspend(struct device *dev)
diff --git a/drivers/staging/greybus/hid.c b/drivers/staging/greybus/hid.c
index 1f58c907c036..f1f9f6fbc00e 100644
--- a/drivers/staging/greybus/hid.c
+++ b/drivers/staging/greybus/hid.c
@@ -201,7 +201,7 @@ static void gb_hid_init_report(struct gb_hid *ghid, struct hid_report *report)
* we just need to setup the input fields, so using
* hid_report_raw_event is safe.
*/
- hid_report_raw_event(ghid->hid, report->type, ghid->inbuf, size, 1);
+ hid_report_raw_event(ghid->hid, report->type, ghid->inbuf, ghid->bufsize, size, 1);
}
static void gb_hid_init_reports(struct gb_hid *ghid)
diff --git a/drivers/staging/greybus/raw.c b/drivers/staging/greybus/raw.c
index 3027a2c25bcd..459aed0f1240 100644
--- a/drivers/staging/greybus/raw.c
+++ b/drivers/staging/greybus/raw.c
@@ -21,9 +21,10 @@ struct gb_raw {
struct list_head list;
int list_data;
struct mutex list_lock;
- dev_t dev;
+ struct rw_semaphore disconnect_lock;
+ bool disconnected;
struct cdev cdev;
- struct device *device;
+ struct device dev;
};
struct raw_data {
@@ -148,6 +149,15 @@ static int gb_raw_send(struct gb_raw *raw, u32 len, const char __user *data)
return retval;
}
+static void raw_dev_release(struct device *dev)
+{
+ struct gb_raw *raw = container_of(dev, struct gb_raw, dev);
+
+ ida_free(&minors, MINOR(raw->dev.devt));
+
+ kfree(raw);
+}
+
static int gb_raw_probe(struct gb_bundle *bundle,
const struct greybus_bundle_id *id)
{
@@ -164,63 +174,59 @@ static int gb_raw_probe(struct gb_bundle *bundle,
if (cport_desc->protocol_id != GREYBUS_PROTOCOL_RAW)
return -ENODEV;
- raw = kzalloc_obj(*raw);
- if (!raw)
+ minor = ida_alloc(&minors, GFP_KERNEL);
+ if (minor < 0)
+ return minor;
+
+ raw = kzalloc_obj(*raw, GFP_KERNEL);
+ if (!raw) {
+ ida_free(&minors, minor);
return -ENOMEM;
+ }
+
+ device_initialize(&raw->dev);
+ raw->dev.devt = MKDEV(raw_major, minor);
+ raw->dev.class = &raw_class;
+ raw->dev.parent = &bundle->dev;
+ raw->dev.release = raw_dev_release;
+ retval = dev_set_name(&raw->dev, "gb!raw%d", minor);
+ if (retval)
+ goto error_put_device;
connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
gb_raw_request_handler);
if (IS_ERR(connection)) {
retval = PTR_ERR(connection);
- goto error_free;
+ goto error_put_device;
}
INIT_LIST_HEAD(&raw->list);
mutex_init(&raw->list_lock);
+ init_rwsem(&raw->disconnect_lock);
raw->connection = connection;
greybus_set_drvdata(bundle, raw);
- minor = ida_alloc(&minors, GFP_KERNEL);
- if (minor < 0) {
- retval = minor;
- goto error_connection_destroy;
- }
-
- raw->dev = MKDEV(raw_major, minor);
cdev_init(&raw->cdev, &raw_fops);
retval = gb_connection_enable(connection);
if (retval)
- goto error_remove_ida;
+ goto error_connection_destroy;
- retval = cdev_add(&raw->cdev, raw->dev, 1);
+ retval = cdev_device_add(&raw->cdev, &raw->dev);
if (retval)
goto error_connection_disable;
- raw->device = device_create(&raw_class, &connection->bundle->dev,
- raw->dev, raw, "gb!raw%d", minor);
- if (IS_ERR(raw->device)) {
- retval = PTR_ERR(raw->device);
- goto error_del_cdev;
- }
-
return 0;
-error_del_cdev:
- cdev_del(&raw->cdev);
-
error_connection_disable:
gb_connection_disable(connection);
-error_remove_ida:
- ida_free(&minors, minor);
-
error_connection_destroy:
gb_connection_destroy(connection);
-error_free:
- kfree(raw);
+error_put_device:
+ put_device(&raw->dev);
return retval;
}
@@ -231,11 +237,13 @@ static void gb_raw_disconnect(struct gb_bundle *bundle)
struct raw_data *raw_data;
struct raw_data *temp;
- // FIXME - handle removing a connection when the char device node is open.
- device_destroy(&raw_class, raw->dev);
- cdev_del(&raw->cdev);
+ cdev_device_del(&raw->cdev, &raw->dev);
+
+ down_write(&raw->disconnect_lock);
+ raw->disconnected = true;
+ up_write(&raw->disconnect_lock);
+
gb_connection_disable(connection);
- ida_free(&minors, MINOR(raw->dev));
gb_connection_destroy(connection);
mutex_lock(&raw->list_lock);
@@ -244,8 +252,7 @@ static void gb_raw_disconnect(struct gb_bundle *bundle)
kfree(raw_data);
}
mutex_unlock(&raw->list_lock);
-
- kfree(raw);
+ put_device(&raw->dev);
}
/*
@@ -278,11 +285,22 @@ static ssize_t raw_write(struct file *file, const char __user *buf,
if (count > MAX_PACKET_SIZE)
return -E2BIG;
+ down_read(&raw->disconnect_lock);
+
+ if (raw->disconnected) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
retval = gb_raw_send(raw, count, buf);
if (retval)
- return retval;
+ goto exit;
+
+ retval = count;
+exit:
+ up_read(&raw->disconnect_lock);
- return count;
+ return retval;
}
static ssize_t raw_read(struct file *file, char __user *buf, size_t count,
diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
index 55a7d8f38465..1bc644f73a9d 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -744,6 +744,28 @@ static int csi_setup(struct csi_priv *priv,
return 0;
}
+static void csi_set_src(struct csi_priv *priv,
+ struct v4l2_mbus_config *mbus_cfg)
+{
+ bool is_csi2;
+
+ is_csi2 = !is_parallel_bus(mbus_cfg);
+ if (is_csi2) {
+ /*
+ * NOTE! It seems the virtual channels from the mipi csi-2
+ * receiver are used only for routing by the video mux's,
+ * or for hard-wired routing to the CSI's. Once the stream
+ * enters the CSI's however, they are treated internally
+ * in the IPU as virtual channel 0.
+ */
+ ipu_csi_set_mipi_datatype(priv->csi, 0,
+ &priv->format_mbus[CSI_SINK_PAD]);
+ }
+
+ /* select either parallel or MIPI-CSI2 as input to CSI */
+ ipu_set_csi_src_mux(priv->ipu, priv->csi_id, is_csi2);
+}
+
static int csi_start(struct csi_priv *priv)
{
struct v4l2_mbus_config mbus_cfg = { .type = 0 };
@@ -760,6 +782,8 @@ static int csi_start(struct csi_priv *priv)
input_fi = &priv->frame_interval[CSI_SINK_PAD];
output_fi = &priv->frame_interval[priv->active_output_pad];
+ csi_set_src(priv, &mbus_cfg);
+
/* start upstream */
ret = v4l2_subdev_call(priv->src_sd, video, s_stream, 1);
ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0;
@@ -1130,7 +1154,6 @@ static int csi_link_validate(struct v4l2_subdev *sd,
{
struct csi_priv *priv = v4l2_get_subdevdata(sd);
struct v4l2_mbus_config mbus_cfg = { .type = 0 };
- bool is_csi2;
int ret;
ret = v4l2_subdev_link_validate_default(sd, link,
@@ -1145,25 +1168,6 @@ static int csi_link_validate(struct v4l2_subdev *sd,
return ret;
}
- mutex_lock(&priv->lock);
-
- is_csi2 = !is_parallel_bus(&mbus_cfg);
- if (is_csi2) {
- /*
- * NOTE! It seems the virtual channels from the mipi csi-2
- * receiver are used only for routing by the video mux's,
- * or for hard-wired routing to the CSI's. Once the stream
- * enters the CSI's however, they are treated internally
- * in the IPU as virtual channel 0.
- */
- ipu_csi_set_mipi_datatype(priv->csi, 0,
- &priv->format_mbus[CSI_SINK_PAD]);
- }
-
- /* select either parallel or MIPI-CSI2 as input to CSI */
- ipu_set_csi_src_mux(priv->ipu, priv->csi_id, is_csi2);
-
- mutex_unlock(&priv->lock);
return ret;
}
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index abe91dc8722e..21f5cb86d70c 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -1187,7 +1187,8 @@ sbc_execute_unmap(struct se_cmd *cmd)
goto err;
}
- if (lba + range > dev->transport->get_blocks(dev) + 1) {
+ if (lba + range < lba ||
+ lba + range > dev->transport->get_blocks(dev) + 1) {
ret = TCM_ADDRESS_OUT_OF_RANGE;
goto err;
}
diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c
index 603dadcd3df5..5e3e9c1f32f8 100644
--- a/drivers/thermal/spear_thermal.c
+++ b/drivers/thermal/spear_thermal.c
@@ -93,7 +93,7 @@ static int spear_thermal_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
int ret = 0, val;
- if (!np || !of_property_read_u32(np, "st,thermal-flags", &val)) {
+ if (!np || of_property_read_u32(np, "st,thermal-flags", &val)) {
dev_err(&pdev->dev, "Failed: DT Pdata not passed\n");
return -EINVAL;
}
diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c
index 1dcdb9e99bd8..37db8a3e5158 100644
--- a/drivers/tty/hvc/hvc_iucv.c
+++ b/drivers/tty/hvc/hvc_iucv.c
@@ -130,7 +130,7 @@ static struct iucv_handler hvc_iucv_handler = {
*/
static struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num)
{
- if (num > hvc_iucv_devices)
+ if (num >= hvc_iucv_devices)
return NULL;
return hvc_iucv_table[num];
}
diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c
index 6e19c6713849..a12101dc0554 100644
--- a/drivers/tty/serial/ip22zilog.c
+++ b/drivers/tty/serial/ip22zilog.c
@@ -1025,7 +1025,7 @@ static struct uart_driver ip22zilog_reg = {
#endif
};
-static void __init ip22zilog_prepare(struct uart_ip22zilog_port *up)
+static void ip22zilog_prepare(struct uart_ip22zilog_port *up)
{
unsigned char sysrq_on = IS_ENABLED(CONFIG_SERIAL_IP22_ZILOG_CONSOLE);
int brg;
diff --git a/drivers/usb/typec/mux/ps883x.c b/drivers/usb/typec/mux/ps883x.c
index 5f2879749769..1256252eceed 100644
--- a/drivers/usb/typec/mux/ps883x.c
+++ b/drivers/usb/typec/mux/ps883x.c
@@ -444,6 +444,7 @@ static int ps883x_retimer_probe(struct i2c_client *client)
goto err_switch_unregister;
}
+ i2c_set_clientdata(client, retimer);
return 0;
err_switch_unregister:
diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c
index e2b26af2b84a..43faec794b95 100644
--- a/drivers/usb/typec/tipd/core.c
+++ b/drivers/usb/typec/tipd/core.c
@@ -820,8 +820,10 @@ static void cd321x_update_work(struct work_struct *work)
desc.identity = &st.partner_identity;
tps->partner = typec_register_partner(tps->port, &desc);
- if (IS_ERR(tps->partner))
- dev_warn(tps->dev, "%s: failed to register partnet\n", __func__);
+ if (IS_ERR(tps->partner)) {
+ dev_warn(tps->dev, "%s: failed to register partner\n", __func__);
+ return;
+ }
if (desc.identity) {
typec_partner_set_identity(tps->partner);
diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c
index 34874beb0152..caf0ee5d6856 100644
--- a/drivers/vdpa/vdpa.c
+++ b/drivers/vdpa/vdpa.c
@@ -67,57 +67,20 @@ static void vdpa_dev_remove(struct device *d)
static int vdpa_dev_match(struct device *dev, const struct device_driver *drv)
{
- struct vdpa_device *vdev = dev_to_vdpa(dev);
+ int ret;
/* Check override first, and if set, only use the named driver */
- if (vdev->driver_override)
- return strcmp(vdev->driver_override, drv->name) == 0;
+ ret = device_match_driver_override(dev, drv);
+ if (ret >= 0)
+ return ret;
/* Currently devices must be supported by all vDPA bus drivers */
return 1;
}
-static ssize_t driver_override_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct vdpa_device *vdev = dev_to_vdpa(dev);
- int ret;
-
- ret = driver_set_override(dev, &vdev->driver_override, buf, count);
- if (ret)
- return ret;
-
- return count;
-}
-
-static ssize_t driver_override_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct vdpa_device *vdev = dev_to_vdpa(dev);
- ssize_t len;
-
- device_lock(dev);
- len = sysfs_emit(buf, "%s\n", vdev->driver_override);
- device_unlock(dev);
-
- return len;
-}
-static DEVICE_ATTR_RW(driver_override);
-
-static struct attribute *vdpa_dev_attrs[] = {
- &dev_attr_driver_override.attr,
- NULL,
-};
-
-static const struct attribute_group vdpa_dev_group = {
- .attrs = vdpa_dev_attrs,
-};
-__ATTRIBUTE_GROUPS(vdpa_dev);
-
static const struct bus_type vdpa_bus = {
.name = "vdpa",
- .dev_groups = vdpa_dev_groups,
+ .driver_override = true,
.match = vdpa_dev_match,
.probe = vdpa_dev_probe,
.remove = vdpa_dev_remove,
@@ -132,7 +95,6 @@ static void vdpa_release_dev(struct device *d)
ops->free(vdev);
ida_free(&vdpa_index_ida, vdev->index);
- kfree(vdev->driver_override);
kfree(vdev);
}
diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc.c b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
index 462fae1aa538..b4c3958201b2 100644
--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
@@ -424,9 +424,7 @@ static int vfio_fsl_mc_bus_notifier(struct notifier_block *nb,
if (action == BUS_NOTIFY_ADD_DEVICE &&
vdev->mc_dev == mc_cont) {
- mc_dev->driver_override = kasprintf(GFP_KERNEL, "%s",
- vfio_fsl_mc_ops.name);
- if (!mc_dev->driver_override)
+ if (device_set_driver_override(dev, vfio_fsl_mc_ops.name))
dev_warn(dev, "VFIO_FSL_MC: Setting driver override for device in dprc %s failed\n",
dev_name(&mc_cont->dev));
else
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index d43745fe4c84..e34c7e1ba1c8 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -734,10 +734,10 @@ void vfio_pci_core_close_device(struct vfio_device *core_vdev)
#if IS_ENABLED(CONFIG_EEH)
eeh_dev_release(vdev->pdev);
#endif
- vfio_pci_core_disable(vdev);
-
vfio_pci_dma_buf_cleanup(vdev);
+ vfio_pci_core_disable(vdev);
+
mutex_lock(&vdev->igate);
vfio_pci_eventfd_replace_locked(vdev, &vdev->err_trigger, NULL);
vfio_pci_eventfd_replace_locked(vdev, &vdev->req_trigger, NULL);
@@ -1670,21 +1670,16 @@ vm_fault_t vfio_pci_vmf_insert_pfn(struct vfio_pci_core_device *vdev,
if (vdev->pm_runtime_engaged || !__vfio_pci_memory_enabled(vdev))
return VM_FAULT_SIGBUS;
- switch (order) {
- case 0:
+ if (!order)
return vmf_insert_pfn(vmf->vma, vmf->address, pfn);
-#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP
- case PMD_ORDER:
+
+ if (IS_ENABLED(CONFIG_ARCH_SUPPORTS_PMD_PFNMAP) && order == PMD_ORDER)
return vmf_insert_pfn_pmd(vmf, pfn, false);
-#endif
-#ifdef CONFIG_ARCH_SUPPORTS_PUD_PFNMAP
- case PUD_ORDER:
+
+ if (IS_ENABLED(CONFIG_ARCH_SUPPORTS_PUD_PFNMAP) && order == PUD_ORDER)
return vmf_insert_pfn_pud(vmf, pfn, false);
- break;
-#endif
- default:
- return VM_FAULT_FALLBACK;
- }
+
+ return VM_FAULT_FALLBACK;
}
EXPORT_SYMBOL_GPL(vfio_pci_vmf_insert_pfn);
@@ -1987,9 +1982,8 @@ static int vfio_pci_bus_notifier(struct notifier_block *nb,
pdev->is_virtfn && physfn == vdev->pdev) {
pci_info(vdev->pdev, "Captured SR-IOV VF %s driver_override\n",
pci_name(pdev));
- pdev->driver_override = kasprintf(GFP_KERNEL, "%s",
- vdev->vdev.ops->name);
- WARN_ON(!pdev->driver_override);
+ WARN_ON(device_set_driver_override(&pdev->dev,
+ vdev->vdev.ops->name));
} else if (action == BUS_NOTIFY_BOUND_DRIVER &&
pdev->is_virtfn && physfn == vdev->pdev) {
struct pci_driver *drv = pci_dev_driver(pdev);
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 80965181920c..c6536cad9c4f 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -560,7 +560,7 @@ static void vhost_net_busy_poll(struct vhost_net *net,
busyloop_timeout = poll_rx ? rvq->busyloop_timeout:
tvq->busyloop_timeout;
- preempt_disable();
+ migrate_disable();
endtime = busy_clock() + busyloop_timeout;
while (vhost_can_busy_poll(endtime)) {
@@ -577,7 +577,7 @@ static void vhost_net_busy_poll(struct vhost_net *net,
cpu_relax();
}
- preempt_enable();
+ migrate_enable();
if (poll_rx || sock_has_rx_data(sock))
vhost_net_busy_poll_try_queue(net, vq);
diff --git a/drivers/video/backlight/sky81452-backlight.c b/drivers/video/backlight/sky81452-backlight.c
index 2749231f0385..b2679b24de14 100644
--- a/drivers/video/backlight/sky81452-backlight.c
+++ b/drivers/video/backlight/sky81452-backlight.c
@@ -202,6 +202,9 @@ static struct sky81452_bl_platform_data *sky81452_bl_parse_dt(
pdata->dpwm_mode = of_property_read_bool(np, "skyworks,dpwm-mode");
pdata->phase_shift = of_property_read_bool(np, "skyworks,phase-shift");
pdata->gpiod_enable = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH);
+ if (IS_ERR(pdata->gpiod_enable))
+ return dev_err_cast_probe(dev, pdata->gpiod_enable,
+ "failed to get gpio\n");
ret = of_property_count_u32_elems(np, "led-sources");
if (ret < 0) {
diff --git a/drivers/video/fbdev/matrox/g450_pll.c b/drivers/video/fbdev/matrox/g450_pll.c
index e2c1478aa47f..6a08f78cd1ac 100644
--- a/drivers/video/fbdev/matrox/g450_pll.c
+++ b/drivers/video/fbdev/matrox/g450_pll.c
@@ -409,7 +409,7 @@ static int __g450_setclk(struct matrox_fb_info *minfo, unsigned int fout,
case M_VIDEO_PLL:
{
u_int8_t tmp;
- unsigned int mnp;
+ unsigned int mnp __maybe_unused;
unsigned long flags;
matroxfb_DAC_lock_irqsave(flags);
diff --git a/drivers/video/fbdev/offb.c b/drivers/video/fbdev/offb.c
index f85428e13996..166b2dff36f5 100644
--- a/drivers/video/fbdev/offb.c
+++ b/drivers/video/fbdev/offb.c
@@ -640,8 +640,13 @@ static void offb_init_nodriver(struct platform_device *parent, struct device_nod
vid = be32_to_cpup(vidp);
did = be32_to_cpup(didp);
pdev = pci_get_device(vid, did, NULL);
- if (!pdev || pci_enable_device(pdev))
+ if (!pdev)
return;
+
+ if (pci_enable_device(pdev)) {
+ pci_dev_put(pdev);
+ return;
+ }
}
#endif
/* kludge for valkyrie */
diff --git a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c b/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
index 0c9ea24a200c..66d00b6ceb78 100644
--- a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
+++ b/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
@@ -157,7 +157,8 @@ static int arm_cca_report_new(struct tsm_report *report, void *data)
} while (info.result == RSI_INCOMPLETE &&
info.offset < RSI_GRANULE_SIZE);
- if (info.result != RSI_SUCCESS) {
+ /* Break out in case of failure */
+ if (info.result != RSI_SUCCESS && info.result != RSI_INCOMPLETE) {
ret = -ENXIO;
token_size = 0;
goto exit_free_granule_page;
diff --git a/drivers/virt/coco/sev-guest/sev-guest.c b/drivers/virt/coco/sev-guest/sev-guest.c
index e001e6769a43..910a1de0d5a7 100644
--- a/drivers/virt/coco/sev-guest/sev-guest.c
+++ b/drivers/virt/coco/sev-guest/sev-guest.c
@@ -176,7 +176,6 @@ static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_reques
struct snp_guest_req req = {};
int ret, npages = 0, resp_len;
sockptr_t certs_address;
- struct page *page;
if (sockptr_is_null(io->req_data) || sockptr_is_null(io->resp_data))
return -EINVAL;
@@ -211,16 +210,15 @@ static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_reques
* zeros to indicate that certificate data was not provided.
*/
npages = report_req->certs_len >> PAGE_SHIFT;
- page = alloc_pages(GFP_KERNEL_ACCOUNT | __GFP_ZERO,
- get_order(report_req->certs_len));
- if (!page)
+ req.certs_data = alloc_pages_exact(npages << PAGE_SHIFT,
+ GFP_KERNEL_ACCOUNT | __GFP_ZERO);
+ if (!req.certs_data)
return -ENOMEM;
- req.certs_data = page_address(page);
ret = set_memory_decrypted((unsigned long)req.certs_data, npages);
if (ret) {
pr_err("failed to mark page shared, ret=%d\n", ret);
- __free_pages(page, get_order(report_req->certs_len));
+ free_pages_exact(req.certs_data, npages << PAGE_SHIFT);
return -EFAULT;
}
@@ -277,7 +275,7 @@ static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_reques
if (set_memory_encrypted((unsigned long)req.certs_data, npages))
WARN_ONCE(ret, "failed to restore encryption mask (leak it)\n");
else
- __free_pages(page, get_order(report_req->certs_len));
+ free_pages_exact(req.certs_data, npages << PAGE_SHIFT);
}
return ret;
}
diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c
index e4b27aecbf05..79a2b5dfd694 100644
--- a/drivers/xen/xen-pciback/pci_stub.c
+++ b/drivers/xen/xen-pciback/pci_stub.c
@@ -598,6 +598,8 @@ static int pcistub_seize(struct pci_dev *dev,
return err;
}
+static struct pci_driver xen_pcibk_pci_driver;
+
/* Called when 'bind'. This means we must _NOT_ call pci_reset_function or
* other functions that take the sysfs lock. */
static int pcistub_probe(struct pci_dev *dev, const struct pci_device_id *id)
@@ -609,8 +611,8 @@ static int pcistub_probe(struct pci_dev *dev, const struct pci_device_id *id)
match = pcistub_match(dev);
- if ((dev->driver_override &&
- !strcmp(dev->driver_override, PCISTUB_DRIVER_NAME)) ||
+ if (device_match_driver_override(&dev->dev,
+ &xen_pcibk_pci_driver.driver) > 0 ||
match) {
if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 2c5b2076acf9..a4cd0a5159dd 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -317,6 +317,9 @@ static int adfs_validate_bblk(struct super_block *sb, struct buffer_head *bh,
if (adfs_checkdiscrecord(dr))
return -EILSEQ;
+ if ((dr->nzones | dr->nzones_high << 8) == 0)
+ return -EILSEQ;
+
*drp = dr;
return 0;
}
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 1b0eb246b714..37ca4ef87902 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -4709,6 +4709,7 @@ static void btrfs_destroy_marked_extents(struct btrfs_fs_info *fs_info,
free_extent_buffer_stale(eb);
}
}
+ btrfs_extent_io_tree_release(dirty_pages);
}
static void btrfs_destroy_pinned_extent(struct btrfs_fs_info *fs_info,
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 2ad2d503e79a..dc2b22e65bad 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -811,7 +811,8 @@ static inline int inode_need_compress(struct btrfs_inode *inode, u64 start,
* do not even bother try compression, as there will be no space saving
* and will always fallback to regular write later.
*/
- if (start != 0 && end + 1 - start <= fs_info->sectorsize)
+ if (end + 1 - start <= fs_info->sectorsize &&
+ (start > 0 || end + 1 < inode->disk_i_size))
return 0;
/* Defrag ioctl takes precedence over mount options and properties. */
if (inode->defrag_compress == BTRFS_DEFRAG_DONT_COMPRESS)
@@ -1244,7 +1245,7 @@ static void submit_one_async_extent(struct async_chunk *async_chunk,
NULL, &cached,
EXTENT_LOCKED | EXTENT_DELALLOC |
EXTENT_DELALLOC_NEW |
- EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING,
+ EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV,
PAGE_UNLOCK | PAGE_START_WRITEBACK |
PAGE_END_WRITEBACK);
if (async_extent->cb)
diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c
index 314cb95ba846..55d8d238e586 100644
--- a/fs/btrfs/reflink.c
+++ b/fs/btrfs/reflink.c
@@ -322,6 +322,51 @@ static int clone_copy_inline_extent(struct btrfs_inode *inode,
ret = copy_inline_to_page(inode, new_key->offset,
inline_data, size, datal, comp_type);
+
+ /*
+ * If we copied the inline extent data to a page/folio beyond the i_size
+ * of the destination inode, then we need to increase the i_size before
+ * we start a transaction to update the inode item. This is to prevent a
+ * deadlock when the flushoncommit mount option is used, which happens
+ * like this:
+ *
+ * 1) Task A clones an inline extent from inode X to an offset of inode
+ * Y that is beyond Y's current i_size. This means we copied the
+ * inline extent's data to a folio of inode Y that is beyond its EOF,
+ * using the call above to copy_inline_to_page();
+ *
+ * 2) Task B starts a transaction commit and calls
+ * btrfs_start_delalloc_flush() to flush delalloc;
+ *
+ * 3) The delalloc flushing sees the new dirty folio of inode Y and when
+ * it attempts to flush it, it ends up at extent_writepage() and sees
+ * that the offset of the folio is beyond the i_size of inode Y, so
+ * it attempts to invalidate the folio by calling folio_invalidate(),
+ * which ends up at btrfs' folio invalidate callback -
+ * btrfs_invalidate_folio(). There it tries to lock the folio's range
+ * in inode Y's extent io tree, but it blocks since it's currently
+ * locked by task A - during reflink we lock the inodes and the
+ * source and destination ranges after flushing all delalloc and
+ * waiting for ordered extent completion - after that we don't expect
+ * to have dirty folios in the ranges, the exception is if we have to
+ * copy an inline extent's data (because the destination offset is
+ * not zero);
+ *
+ * 4) Task A then does the 'goto out' below and attempts to start a
+ * transaction to update the inode item, and then it's blocked since
+ * the current transaction is in the TRANS_STATE_COMMIT_START state.
+ * Therefore task A has to wait for the current transaction to become
+ * unblocked (its state >= TRANS_STATE_UNBLOCKED).
+ *
+ * This leads to a deadlock - the task committing the transaction
+ * waiting for the delalloc flushing which is blocked during folio
+ * invalidation on the inode's extent lock and the reflink task waiting
+ * for the current transaction to be unblocked so that it can start a
+ * a new one to update the inode item (while holding the extent lock).
+ */
+ if (ret == 0 && new_key->offset + datal > i_size_read(&inode->vfs_inode))
+ i_size_write(&inode->vfs_inode, new_key->offset + datal);
+
goto out;
}
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 033f74fd6225..d8cd04fe9a4c 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -3884,7 +3884,7 @@ static int add_remap_tree_entries(struct btrfs_trans_handle *trans, struct btrfs
ret = btrfs_insert_empty_items(trans, fs_info->remap_root, path, &batch);
btrfs_release_path(path);
- if (num_entries <= max_items)
+ if (ret || num_entries <= max_items)
break;
num_entries -= max_items;
@@ -4182,6 +4182,12 @@ static int move_existing_remap(struct btrfs_fs_info *fs_info,
return ret;
}
+ if (ins.offset < length) {
+ spin_lock(&sinfo->lock);
+ btrfs_space_info_update_bytes_may_use(sinfo, ins.offset - length);
+ spin_unlock(&sinfo->lock);
+ }
+
dest_addr = ins.objectid;
dest_length = ins.offset;
@@ -5008,6 +5014,12 @@ static int do_remap_reloc_trans(struct btrfs_fs_info *fs_info,
return ret;
}
+ if (ins.offset < remap_length) {
+ spin_lock(&sinfo->lock);
+ btrfs_space_info_update_bytes_may_use(sinfo, ins.offset - remap_length);
+ spin_unlock(&sinfo->lock);
+ }
+
made_reservation = true;
new_addr = ins.objectid;
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 8dd77c431974..ec3c15fc7ae3 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -1275,14 +1275,13 @@ static int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans)
blk_finish_plug(&plug);
ret2 = btrfs_wait_extents(fs_info, dirty_pages);
- btrfs_extent_io_tree_release(&trans->transaction->dirty_pages);
-
if (ret)
return ret;
- else if (ret2)
+ if (ret2)
return ret2;
- else
- return 0;
+
+ btrfs_extent_io_tree_release(&trans->transaction->dirty_pages);
+ return 0;
}
/*
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 6b8e810a35ce..fd400fbc654d 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -8457,7 +8457,12 @@ bool btrfs_verify_dev_items(const struct btrfs_fs_info *fs_info)
mutex_lock(&uuid_mutex);
list_for_each_entry(dev, &fs_info->fs_devices->devices, dev_list) {
- if (!test_bit(BTRFS_DEV_STATE_ITEM_FOUND, &dev->dev_state)) {
+ /*
+ * Replace target dev item (devid 0) is not inserted into chunk tree.
+ * So skip the DEV_STATE_ITEM check.
+ */
+ if (dev->devid != BTRFS_DEV_REPLACE_DEVID &&
+ !test_bit(BTRFS_DEV_STATE_ITEM_FOUND, &dev->dev_state)) {
btrfs_err(fs_info,
"devid %llu path %s is registered but not found in chunk tree",
dev->devid, btrfs_dev_name(dev));
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 44553556ac74..0c01fcb73ddd 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -1322,6 +1322,7 @@ void ceph_process_folio_batch(struct address_space *mapping,
ceph_wbc, folio);
if (rc == -ENODATA) {
folio_unlock(folio);
+ folio_put(folio);
ceph_wbc->fbatch.folios[i] = NULL;
continue;
} else if (rc == -E2BIG) {
@@ -1332,6 +1333,7 @@ void ceph_process_folio_batch(struct address_space *mapping,
if (!folio_clear_dirty_for_io(folio)) {
doutc(cl, "%p !folio_clear_dirty_for_io\n", folio);
folio_unlock(folio);
+ folio_put(folio);
ceph_wbc->fbatch.folios[i] = NULL;
continue;
}
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c
index 5f87f62091a1..e773be07f767 100644
--- a/fs/ceph/xattr.c
+++ b/fs/ceph/xattr.c
@@ -1254,6 +1254,22 @@ int __ceph_setxattr(struct inode *inode, const char *name,
ceph_vinop(inode), name, ceph_cap_string(issued));
__build_xattrs(inode);
+ /*
+ * __build_xattrs() may have released and reacquired i_ceph_lock,
+ * during which handle_cap_grant() could have replaced i_xattrs.blob
+ * with a newer MDS-provided blob and bumped i_xattrs.version. If that
+ * caused __build_xattrs() to rebuild the rb-tree from the new blob,
+ * count/names_size/vals_size may now be larger than when
+ * required_blob_size was computed above. Recompute it here so the
+ * prealloc_blob size check below reflects the current tree state.
+ */
+ required_blob_size = __get_required_blob_size(ci, name_len, val_len);
+ if (required_blob_size > mdsc->mdsmap->m_max_xattr_size) {
+ doutc(cl, "sync (size too large): %d > %llu\n",
+ required_blob_size, mdsc->mdsmap->m_max_xattr_size);
+ goto do_sync;
+ }
+
if (!ci->i_xattrs.prealloc_blob ||
required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) {
struct ceph_buffer *blob;
@@ -1294,6 +1310,7 @@ int __ceph_setxattr(struct inode *inode, const char *name,
do_sync:
spin_unlock(&ci->i_ceph_lock);
+ ceph_buffer_put(old_blob);
do_sync_unlocked:
if (lock_snap_rwsem)
up_read(&mdsc->snap_rwsem);
diff --git a/fs/d_path.c b/fs/d_path.c
index bb365511066b..a48957c0971e 100644
--- a/fs/d_path.c
+++ b/fs/d_path.c
@@ -301,18 +301,19 @@ EXPORT_SYMBOL(d_path);
char *dynamic_dname(char *buffer, int buflen, const char *fmt, ...)
{
va_list args;
- char temp[64];
+ char *start;
int sz;
va_start(args, fmt);
- sz = vsnprintf(temp, sizeof(temp), fmt, args) + 1;
+ sz = vsnprintf(buffer, buflen, fmt, args) + 1;
va_end(args);
- if (sz > sizeof(temp) || sz > buflen)
+ if (sz > NAME_MAX || sz > buflen)
return ERR_PTR(-ENAMETOOLONG);
- buffer += buflen - sz;
- return memcpy(buffer, temp, sz);
+ /* Move the formatted d_name to the end of the buffer. */
+ start = buffer + (buflen - sz);
+ return memmove(start, buffer, sz);
}
char *simple_dname(struct dentry *dentry, char *buffer, int buflen)
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index 3376ab6a519d..edd6aafbfbaa 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -1047,7 +1047,6 @@ ssize_t debugfs_read_file_str(struct file *file, char __user *user_buf,
return ret;
}
-EXPORT_SYMBOL_GPL(debugfs_create_str);
static ssize_t debugfs_write_file_str(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
@@ -1127,7 +1126,7 @@ static const struct file_operations fops_str_wo = {
* directory dentry if set. If this parameter is %NULL, then the
* file will be created in the root of the debugfs filesystem.
* @value: a pointer to the variable that the file should read to and write
- * from.
+ * from. This pointer and the string it points to must not be %NULL.
*
* This function creates a file in debugfs with the given name that
* contains the value of the variable @value. If the @mode variable is so
@@ -1136,9 +1135,13 @@ static const struct file_operations fops_str_wo = {
void debugfs_create_str(const char *name, umode_t mode,
struct dentry *parent, char **value)
{
+ if (WARN_ON(!value || !*value))
+ return;
+
debugfs_create_mode_unsafe(name, mode, parent, value, &fops_str,
&fops_str_ro, &fops_str_wo);
}
+EXPORT_SYMBOL_GPL(debugfs_create_str);
static ssize_t read_file_blob(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h
index b80c6bb33a58..7871b16c1d33 100644
--- a/fs/erofs/erofs_fs.h
+++ b/fs/erofs/erofs_fs.h
@@ -44,9 +44,9 @@ struct erofs_deviceslot {
u8 tag[64]; /* digest(sha256), etc. */
__le32 blocks_lo; /* total blocks count of this device */
__le32 uniaddr_lo; /* unified starting block of this device */
- __le32 blocks_hi; /* total blocks count MSB */
+ __le16 blocks_hi; /* total blocks count MSB */
__le16 uniaddr_hi; /* unified starting block MSB */
- u8 reserved[50];
+ u8 reserved[52];
};
#define EROFS_DEVT_SLOT_SIZE sizeof(struct erofs_deviceslot)
diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c
index 4b3d21402e10..a188c570087a 100644
--- a/fs/erofs/inode.c
+++ b/fs/erofs/inode.c
@@ -351,7 +351,7 @@ static int erofs_ioctl_get_volume_label(struct inode *inode, void __user *arg)
ret = clear_user(arg, 1);
else
ret = copy_to_user(arg, sbi->volume_name,
- strlen(sbi->volume_name));
+ strlen(sbi->volume_name) + 1);
return ret ? -EFAULT : 0;
}
diff --git a/fs/erofs/super.c b/fs/erofs/super.c
index 972a0c82198d..802add6652fd 100644
--- a/fs/erofs/super.c
+++ b/fs/erofs/super.c
@@ -129,6 +129,7 @@ static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb,
struct erofs_fscache *fscache;
struct erofs_deviceslot *dis;
struct file *file;
+ bool _48bit;
dis = erofs_read_metabuf(buf, sb, *pos, false);
if (IS_ERR(dis))
@@ -175,8 +176,11 @@ static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb,
dif->file = file;
}
- dif->blocks = le32_to_cpu(dis->blocks_lo);
- dif->uniaddr = le32_to_cpu(dis->uniaddr_lo);
+ _48bit = erofs_sb_has_48bit(sbi);
+ dif->blocks = le32_to_cpu(dis->blocks_lo) |
+ (_48bit ? (u64)le16_to_cpu(dis->blocks_hi) << 32 : 0);
+ dif->uniaddr = le32_to_cpu(dis->uniaddr_lo) |
+ (_48bit ? (u64)le16_to_cpu(dis->uniaddr_hi) << 32 : 0);
sbi->total_blocks += dif->blocks;
*pos += EROFS_DEVT_SLOT_SIZE;
return 0;
diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c
index 30775502b56d..abf7ddc64c63 100644
--- a/fs/erofs/zmap.c
+++ b/fs/erofs/zmap.c
@@ -10,7 +10,7 @@
struct z_erofs_maprecorder {
struct inode *inode;
struct erofs_map_blocks *map;
- unsigned long lcn;
+ u64 lcn;
/* compression extent information gathered */
u8 type, headtype;
u16 clusterofs;
@@ -20,8 +20,7 @@ struct z_erofs_maprecorder {
bool partialref, in_mbox;
};
-static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m,
- unsigned long lcn)
+static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m, u64 lcn)
{
struct inode *const inode = m->inode;
struct erofs_inode *const vi = EROFS_I(inode);
@@ -94,7 +93,7 @@ static int get_compacted_la_distance(unsigned int lobits,
}
static int z_erofs_load_compact_lcluster(struct z_erofs_maprecorder *m,
- unsigned long lcn, bool lookahead)
+ u64 lcn, bool lookahead)
{
struct inode *const inode = m->inode;
struct erofs_inode *const vi = EROFS_I(inode);
@@ -234,7 +233,7 @@ static int z_erofs_load_compact_lcluster(struct z_erofs_maprecorder *m,
}
static int z_erofs_load_lcluster_from_disk(struct z_erofs_maprecorder *m,
- unsigned int lcn, bool lookahead)
+ u64 lcn, bool lookahead)
{
struct erofs_inode *vi = EROFS_I(m->inode);
int err;
@@ -249,7 +248,7 @@ static int z_erofs_load_lcluster_from_disk(struct z_erofs_maprecorder *m,
return err;
if (m->type >= Z_EROFS_LCLUSTER_TYPE_MAX) {
- erofs_err(m->inode->i_sb, "unknown type %u @ lcn %u of nid %llu",
+ erofs_err(m->inode->i_sb, "unknown type %u @ lcn %llu of nid %llu",
m->type, lcn, EROFS_I(m->inode)->nid);
DBG_BUGON(1);
return -EOPNOTSUPP;
@@ -269,7 +268,7 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,
const unsigned int lclusterbits = vi->z_lclusterbits;
while (m->lcn >= lookback_distance) {
- unsigned long lcn = m->lcn - lookback_distance;
+ u64 lcn = m->lcn - lookback_distance;
int err;
if (!lookback_distance)
@@ -286,7 +285,7 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,
m->map->m_la = (lcn << lclusterbits) | m->clusterofs;
return 0;
}
- erofs_err(sb, "bogus lookback distance %u @ lcn %lu of nid %llu",
+ erofs_err(sb, "bogus lookback distance %u @ lcn %llu of nid %llu",
lookback_distance, m->lcn, vi->nid);
DBG_BUGON(1);
return -EFSCORRUPTED;
@@ -300,7 +299,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,
struct erofs_inode *vi = EROFS_I(inode);
bool bigpcl1 = vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1;
bool bigpcl2 = vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_2;
- unsigned long lcn = m->lcn + 1;
+ u64 lcn = m->lcn + 1;
int err;
DBG_BUGON(m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD);
@@ -331,7 +330,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,
m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD);
if (m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD && m->delta[0] != 1) {
- erofs_err(sb, "bogus CBLKCNT @ lcn %lu of nid %llu", lcn, vi->nid);
+ erofs_err(sb, "bogus CBLKCNT @ lcn %llu of nid %llu", lcn, vi->nid);
DBG_BUGON(1);
return -EFSCORRUPTED;
}
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 4b43bf41296d..8c03de028c48 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -827,36 +827,47 @@ static void ep_free(struct eventpoll *ep)
}
/*
- * Removes a "struct epitem" from the eventpoll RB tree and deallocates
- * all the associated resources. Must be called with "mtx" held.
- * If the dying flag is set, do the removal only if force is true.
- * This prevents ep_clear_and_put() from dropping all the ep references
- * while running concurrently with eventpoll_release_file().
- * Returns true if the eventpoll can be disposed.
+ * The ffd.file pointer may be in the process of being torn down due to
+ * being closed, but we may not have finished eventpoll_release() yet.
+ *
+ * Normally, even with the atomic_long_inc_not_zero, the file may have
+ * been free'd and then gotten re-allocated to something else (since
+ * files are not RCU-delayed, they are SLAB_TYPESAFE_BY_RCU).
+ *
+ * But for epoll, users hold the ep->mtx mutex, and as such any file in
+ * the process of being free'd will block in eventpoll_release_file()
+ * and thus the underlying file allocation will not be free'd, and the
+ * file re-use cannot happen.
+ *
+ * For the same reason we can avoid a rcu_read_lock() around the
+ * operation - 'ffd.file' cannot go away even if the refcount has
+ * reached zero (but we must still not call out to ->poll() functions
+ * etc).
*/
-static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
+static struct file *epi_fget(const struct epitem *epi)
{
- struct file *file = epi->ffd.file;
- struct epitems_head *to_free;
- struct hlist_head *head;
+ struct file *file;
- lockdep_assert_irqs_enabled();
+ file = epi->ffd.file;
+ if (!file_ref_get(&file->f_ref))
+ file = NULL;
+ return file;
+}
- /*
- * Removes poll wait queue hooks.
- */
- ep_unregister_pollwait(ep, epi);
+/*
+ * Called with &file->f_lock held,
+ * returns with it released
+ */
+static void ep_remove_file(struct eventpoll *ep, struct epitem *epi,
+ struct file *file)
+{
+ struct epitems_head *to_free = NULL;
+ struct hlist_head *head = file->f_ep;
- /* Remove the current item from the list of epoll hooks */
- spin_lock(&file->f_lock);
- if (epi->dying && !force) {
- spin_unlock(&file->f_lock);
- return false;
- }
+ lockdep_assert_held(&ep->mtx);
+ lockdep_assert_held(&file->f_lock);
- to_free = NULL;
- head = file->f_ep;
- if (head->first == &epi->fllink && !epi->fllink.next) {
+ if (hlist_is_singular_node(&epi->fllink, head)) {
/* See eventpoll_release() for details. */
WRITE_ONCE(file->f_ep, NULL);
if (!is_file_epoll(file)) {
@@ -869,6 +880,11 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
hlist_del_rcu(&epi->fllink);
spin_unlock(&file->f_lock);
free_ephead(to_free);
+}
+
+static bool ep_remove_epi(struct eventpoll *ep, struct epitem *epi)
+{
+ lockdep_assert_held(&ep->mtx);
rb_erase_cached(&epi->rbn, &ep->rbr);
@@ -896,7 +912,29 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
*/
static void ep_remove_safe(struct eventpoll *ep, struct epitem *epi)
{
- if (__ep_remove(ep, epi, false))
+ struct file *file __free(fput) = NULL;
+
+ lockdep_assert_irqs_enabled();
+ lockdep_assert_held(&ep->mtx);
+
+ ep_unregister_pollwait(ep, epi);
+
+ /* cheap sync with eventpoll_release_file() */
+ if (unlikely(READ_ONCE(epi->dying)))
+ return;
+
+ /*
+ * If we manage to grab a reference it means we're not in
+ * eventpoll_release_file() and aren't going to be.
+ */
+ file = epi_fget(epi);
+ if (!file)
+ return;
+
+ spin_lock(&file->f_lock);
+ ep_remove_file(ep, epi, file);
+
+ if (ep_remove_epi(ep, epi))
WARN_ON_ONCE(ep_refcount_dec_and_test(ep));
}
@@ -1012,34 +1050,6 @@ static __poll_t __ep_eventpoll_poll(struct file *file, poll_table *wait, int dep
return res;
}
-/*
- * The ffd.file pointer may be in the process of being torn down due to
- * being closed, but we may not have finished eventpoll_release() yet.
- *
- * Normally, even with the atomic_long_inc_not_zero, the file may have
- * been free'd and then gotten re-allocated to something else (since
- * files are not RCU-delayed, they are SLAB_TYPESAFE_BY_RCU).
- *
- * But for epoll, users hold the ep->mtx mutex, and as such any file in
- * the process of being free'd will block in eventpoll_release_file()
- * and thus the underlying file allocation will not be free'd, and the
- * file re-use cannot happen.
- *
- * For the same reason we can avoid a rcu_read_lock() around the
- * operation - 'ffd.file' cannot go away even if the refcount has
- * reached zero (but we must still not call out to ->poll() functions
- * etc).
- */
-static struct file *epi_fget(const struct epitem *epi)
-{
- struct file *file;
-
- file = epi->ffd.file;
- if (!file_ref_get(&file->f_ref))
- file = NULL;
- return file;
-}
-
/*
* Differs from ep_eventpoll_poll() in that internal callers already have
* the ep->mtx so we need to start from depth=1, such that mutex_lock_nested()
@@ -1128,7 +1138,7 @@ void eventpoll_release_file(struct file *file)
spin_lock(&file->f_lock);
if (file->f_ep && file->f_ep->first) {
epi = hlist_entry(file->f_ep->first, struct epitem, fllink);
- epi->dying = true;
+ WRITE_ONCE(epi->dying, true);
spin_unlock(&file->f_lock);
/*
@@ -1137,7 +1147,13 @@ void eventpoll_release_file(struct file *file)
*/
ep = epi->ep;
mutex_lock(&ep->mtx);
- dispose = __ep_remove(ep, epi, true);
+
+ ep_unregister_pollwait(ep, epi);
+
+ spin_lock(&file->f_lock);
+ ep_remove_file(ep, epi, file);
+ dispose = ep_remove_epi(ep, epi);
+
mutex_unlock(&ep->mtx);
if (dispose && ep_refcount_dec_and_test(ep))
diff --git a/fs/ext4/extents-test.c b/fs/ext4/extents-test.c
index 5496b2c8e2cd..6b53a3f39fcd 100644
--- a/fs/ext4/extents-test.c
+++ b/fs/ext4/extents-test.c
@@ -142,10 +142,14 @@ static struct file_system_type ext_fs_type = {
static void extents_kunit_exit(struct kunit *test)
{
- struct super_block *sb = k_ctx.k_ei->vfs_inode.i_sb;
- struct ext4_sb_info *sbi = sb->s_fs_info;
+ struct ext4_sb_info *sbi;
+ if (!k_ctx.k_ei)
+ return;
+
+ sbi = k_ctx.k_ei->vfs_inode.i_sb->s_fs_info;
ext4_es_unregister_shrinker(sbi);
+ deactivate_super(sbi->s_sb);
kfree(sbi);
kfree(k_ctx.k_ei);
kfree(k_ctx.k_data);
@@ -224,34 +228,38 @@ static int extents_kunit_init(struct kunit *test)
(struct kunit_ext_test_param *)(test->param_value);
int err;
- sb = sget(&ext_fs_type, NULL, ext_set, 0, NULL);
- if (IS_ERR(sb))
- return PTR_ERR(sb);
-
- sb->s_blocksize = 4096;
- sb->s_blocksize_bits = 12;
-
sbi = kzalloc_obj(struct ext4_sb_info);
if (sbi == NULL)
return -ENOMEM;
+ sb = sget(&ext_fs_type, NULL, ext_set, 0, NULL);
+ if (IS_ERR(sb)) {
+ kfree(sbi);
+ return PTR_ERR(sb);
+ }
+
sbi->s_sb = sb;
sb->s_fs_info = sbi;
+ sb->s_blocksize = 4096;
+ sb->s_blocksize_bits = 12;
+
if (!param || !param->disable_zeroout)
sbi->s_extent_max_zeroout_kb = 32;
+ err = ext4_es_register_shrinker(sbi);
+ if (err)
+ goto out_deactivate;
+
/* setup the mock inode */
k_ctx.k_ei = kzalloc_obj(struct ext4_inode_info);
- if (k_ctx.k_ei == NULL)
- return -ENOMEM;
+ if (k_ctx.k_ei == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
ei = k_ctx.k_ei;
inode = &ei->vfs_inode;
- err = ext4_es_register_shrinker(sbi);
- if (err)
- return err;
-
ext4_es_init_tree(&ei->i_es_tree);
rwlock_init(&ei->i_es_lock);
INIT_LIST_HEAD(&ei->i_es_list);
@@ -266,8 +274,10 @@ static int extents_kunit_init(struct kunit *test)
inode->i_sb = sb;
k_ctx.k_data = kzalloc(EXT_DATA_LEN * 4096, GFP_KERNEL);
- if (k_ctx.k_data == NULL)
- return -ENOMEM;
+ if (k_ctx.k_data == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
/*
* set the data area to a junk value
@@ -309,7 +319,23 @@ static int extents_kunit_init(struct kunit *test)
kunit_activate_static_stub(test, ext4_ext_zeroout, ext4_ext_zeroout_stub);
kunit_activate_static_stub(test, ext4_issue_zeroout,
ext4_issue_zeroout_stub);
+ up_write(&sb->s_umount);
+
return 0;
+
+out:
+ kfree(k_ctx.k_ei);
+ k_ctx.k_ei = NULL;
+
+ kfree(k_ctx.k_data);
+ k_ctx.k_data = NULL;
+
+ ext4_es_unregister_shrinker(sbi);
+out_deactivate:
+ deactivate_locked_super(sb);
+ kfree(sbi);
+
+ return err;
}
/*
diff --git a/fs/ext4/mballoc-test.c b/fs/ext4/mballoc-test.c
index 6f5bfbb0e8a4..95cb644cd32f 100644
--- a/fs/ext4/mballoc-test.c
+++ b/fs/ext4/mballoc-test.c
@@ -362,7 +362,6 @@ static int mbt_kunit_init(struct kunit *test)
return ret;
}
- test->priv = sb;
kunit_activate_static_stub(test,
ext4_read_block_bitmap_nowait,
ext4_read_block_bitmap_nowait_stub);
@@ -383,6 +382,8 @@ static int mbt_kunit_init(struct kunit *test)
return -ENOMEM;
}
+ test->priv = sb;
+
return 0;
}
@@ -390,6 +391,9 @@ static void mbt_kunit_exit(struct kunit *test)
{
struct super_block *sb = (struct super_block *)test->priv;
+ if (!sb)
+ return;
+
mbt_mb_release(sb);
mbt_ctx_release(sb);
mbt_ext4_free_super_block(sb);
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index f46b2673d31f..ec0680187c0d 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -1230,7 +1230,7 @@ static int ra_data_block(struct inode *inode, pgoff_t index)
.encrypted_page = NULL,
.in_list = 0,
};
- int err;
+ int err = 0;
folio = f2fs_grab_cache_folio(mapping, index, true);
if (IS_ERR(folio))
@@ -1283,6 +1283,9 @@ static int ra_data_block(struct inode *inode, pgoff_t index)
fio.encrypted_page = &efolio->page;
+ if (folio_test_uptodate(efolio))
+ goto put_encrypted_page;
+
err = f2fs_submit_page_bio(&fio);
if (err)
goto put_encrypted_page;
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 9ff954952a15..a2ead811c316 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -427,7 +427,9 @@ bool f2fs_need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino)
struct f2fs_nm_info *nm_i = NM_I(sbi);
struct nat_entry *e;
bool need_update = true;
+ struct f2fs_lock_context lc;
+ f2fs_down_read_trace(&sbi->node_write, &lc);
f2fs_down_read(&nm_i->nat_tree_lock);
e = __lookup_nat_cache(nm_i, ino, false);
if (e && get_nat_flag(e, HAS_LAST_FSYNC) &&
@@ -435,6 +437,7 @@ bool f2fs_need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino)
get_nat_flag(e, HAS_FSYNCED_INODE)))
need_update = false;
f2fs_up_read(&nm_i->nat_tree_lock);
+ f2fs_up_read_trace(&sbi->node_write, &lc);
return need_update;
}
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 255db40c49ed..79cc7b39802f 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -336,9 +336,12 @@ static const struct fs_parameter_spec f2fs_param_specs[] = {
fsparam_flag("usrquota", Opt_usrquota),
fsparam_flag("grpquota", Opt_grpquota),
fsparam_flag("prjquota", Opt_prjquota),
- fsparam_string_empty("usrjquota", Opt_usrjquota),
- fsparam_string_empty("grpjquota", Opt_grpjquota),
- fsparam_string_empty("prjjquota", Opt_prjjquota),
+ fsparam_string("usrjquota", Opt_usrjquota),
+ fsparam_flag("usrjquota", Opt_usrjquota),
+ fsparam_string("grpjquota", Opt_grpjquota),
+ fsparam_flag("grpjquota", Opt_grpjquota),
+ fsparam_string("prjjquota", Opt_prjjquota),
+ fsparam_flag("prjjquota", Opt_prjjquota),
fsparam_flag("nat_bits", Opt_nat_bits),
fsparam_enum("jqfmt", Opt_jqfmt, f2fs_param_jqfmt),
fsparam_enum("alloc_mode", Opt_alloc, f2fs_param_alloc_mode),
@@ -979,26 +982,26 @@ static int f2fs_parse_param(struct fs_context *fc, struct fs_parameter *param)
ctx_set_opt(ctx, F2FS_MOUNT_PRJQUOTA);
break;
case Opt_usrjquota:
- if (!*param->string)
- ret = f2fs_unnote_qf_name(fc, USRQUOTA);
- else
+ if (param->type == fs_value_is_string && *param->string)
ret = f2fs_note_qf_name(fc, USRQUOTA, param);
+ else
+ ret = f2fs_unnote_qf_name(fc, USRQUOTA);
if (ret)
return ret;
break;
case Opt_grpjquota:
- if (!*param->string)
- ret = f2fs_unnote_qf_name(fc, GRPQUOTA);
- else
+ if (param->type == fs_value_is_string && *param->string)
ret = f2fs_note_qf_name(fc, GRPQUOTA, param);
+ else
+ ret = f2fs_unnote_qf_name(fc, GRPQUOTA);
if (ret)
return ret;
break;
case Opt_prjjquota:
- if (!*param->string)
- ret = f2fs_unnote_qf_name(fc, PRJQUOTA);
- else
+ if (param->type == fs_value_is_string && *param->string)
ret = f2fs_note_qf_name(fc, PRJQUOTA, param);
+ else
+ ret = f2fs_unnote_qf_name(fc, PRJQUOTA);
if (ret)
return ret;
break;
@@ -1515,6 +1518,7 @@ static int f2fs_check_opt_consistency(struct fs_context *fc,
F2FS_OPTION(sbi).root_reserved_blocks);
ctx_clear_opt(ctx, F2FS_MOUNT_RESERVE_ROOT);
ctx->opt_mask &= ~BIT(F2FS_MOUNT_RESERVE_ROOT);
+ ctx->spec_mask &= ~F2FS_SPEC_reserve_root;
}
if (test_opt(sbi, RESERVE_NODE) &&
(ctx->opt_mask & BIT(F2FS_MOUNT_RESERVE_NODE)) &&
@@ -1523,6 +1527,7 @@ static int f2fs_check_opt_consistency(struct fs_context *fc,
F2FS_OPTION(sbi).root_reserved_nodes);
ctx_clear_opt(ctx, F2FS_MOUNT_RESERVE_NODE);
ctx->opt_mask &= ~BIT(F2FS_MOUNT_RESERVE_NODE);
+ ctx->spec_mask &= ~F2FS_SPEC_reserve_node;
}
err = f2fs_check_test_dummy_encryption(fc, sb);
diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
index cd1921edb59e..0d05ecd64ca0 100644
--- a/fs/f2fs/sysfs.c
+++ b/fs/f2fs/sysfs.c
@@ -379,10 +379,12 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
if (!strcmp(a->attr.name, "extension_list")) {
__u8 (*extlist)[F2FS_EXTENSION_LEN] =
sbi->raw_super->extension_list;
- int cold_count = le32_to_cpu(sbi->raw_super->extension_count);
- int hot_count = sbi->raw_super->hot_ext_count;
+ int cold_count, hot_count;
int len = 0, i;
+ f2fs_down_read(&sbi->sb_lock);
+ cold_count = le32_to_cpu(sbi->raw_super->extension_count);
+ hot_count = sbi->raw_super->hot_ext_count;
len += sysfs_emit_at(buf, len, "cold file extension:\n");
for (i = 0; i < cold_count; i++)
len += sysfs_emit_at(buf, len, "%s\n", extlist[i]);
@@ -390,6 +392,7 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
len += sysfs_emit_at(buf, len, "hot file extension:\n");
for (i = cold_count; i < cold_count + hot_count; i++)
len += sysfs_emit_at(buf, len, "%s\n", extlist[i]);
+ f2fs_up_read(&sbi->sb_lock);
return len;
}
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 7ac6b232ef12..d3acfd346ab5 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -481,6 +481,11 @@ static int fuse_dentry_init(struct dentry *dentry)
fd->dentry = dentry;
RB_CLEAR_NODE(&fd->node);
dentry->d_fsdata = fd;
+ /*
+ * Initialising d_time (epoch) to '0' ensures the dentry is invalid
+ * if compared to fc->epoch, which is initialized to '1'.
+ */
+ dentry->d_time = 0;
return 0;
}
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index e79ad087512a..6a6ded7a61d2 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -158,6 +158,7 @@ static int gfs2_writepages(struct address_space *mapping,
struct writeback_control *wbc)
{
struct gfs2_sbd *sdp = gfs2_mapping2sbd(mapping);
+ long initial_nr_to_write = wbc->nr_to_write;
struct iomap_writepage_ctx wpc = {
.inode = mapping->host,
.wbc = wbc,
@@ -166,13 +167,13 @@ static int gfs2_writepages(struct address_space *mapping,
int ret;
/*
- * Even if we didn't write enough pages here, we might still be holding
+ * Even if we didn't write any pages here, we might still be holding
* dirty pages in the ail. We forcibly flush the ail because we don't
* want balance_dirty_pages() to loop indefinitely trying to write out
* pages held in the ail that it can't find.
*/
ret = iomap_writepages(&wpc);
- if (ret == 0 && wbc->nr_to_write > 0)
+ if (ret == 0 && wbc->nr_to_write == initial_nr_to_write)
set_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags);
return ret;
}
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 8344040ecaf7..e9bf4879c07f 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -892,7 +892,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
goto fail_gunlock4;
mark_inode_dirty(inode);
- d_instantiate(dentry, inode);
+ d_instantiate_new(dentry, inode);
/* After instantiate, errors should result in evict which will destroy
* both inode and iopen glocks properly. */
if (file) {
@@ -904,7 +904,6 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
gfs2_glock_dq_uninit(&gh);
gfs2_glock_put(io_gl);
gfs2_qa_put(dip);
- unlock_new_inode(inode);
return error;
fail_gunlock4:
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index 347df29d610e..c483d3c7be69 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -467,8 +467,9 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks)
{
atomic_add(blks, &sdp->sd_log_blks_free);
trace_gfs2_log_blocks(sdp, blks);
- gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <=
- sdp->sd_jdesc->jd_blocks);
+ gfs2_assert_withdraw(sdp, !sdp->sd_jdesc ||
+ atomic_read(&sdp->sd_log_blks_free) <=
+ sdp->sd_jdesc->jd_blocks);
if (atomic_read(&sdp->sd_log_blks_needed))
wake_up(&sdp->sd_log_waitq);
}
@@ -1018,14 +1019,15 @@ static void trans_drain(struct gfs2_trans *tr)
}
/**
- * gfs2_log_flush - flush incore transaction(s)
+ * __gfs2_log_flush - flush incore transaction(s)
* @sdp: The filesystem
* @gl: The glock structure to flush. If NULL, flush the whole incore log
* @flags: The log header flags: GFS2_LOG_HEAD_FLUSH_* and debug flags
*
*/
-void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
+static void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
+ u32 flags)
{
struct gfs2_trans *tr = NULL;
unsigned int reserved_blocks = 0, used_blocks = 0;
@@ -1033,7 +1035,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
unsigned int first_log_head;
unsigned int reserved_revokes = 0;
- down_write(&sdp->sd_log_flush_lock);
trace_gfs2_log_flush(sdp, 1, flags);
repeat:
@@ -1145,7 +1146,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
gfs2_assert_withdraw(sdp, used_blocks < reserved_blocks);
gfs2_log_release(sdp, reserved_blocks - used_blocks);
}
- up_write(&sdp->sd_log_flush_lock);
gfs2_trans_free(sdp, tr);
trace_gfs2_log_flush(sdp, 0, flags);
return;
@@ -1166,6 +1166,13 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
goto out_end;
}
+void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
+{
+ down_write(&sdp->sd_log_flush_lock);
+ __gfs2_log_flush(sdp, gl, flags);
+ up_write(&sdp->sd_log_flush_lock);
+}
+
/**
* gfs2_merge_trans - Merge a new transaction into a cached transaction
* @sdp: the filesystem
@@ -1297,19 +1304,25 @@ int gfs2_logd(void *data)
break;
if (gfs2_jrnl_flush_reqd(sdp) || t == 0) {
+ down_write(&sdp->sd_log_flush_lock);
gfs2_ail1_empty(sdp, 0);
- gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL |
- GFS2_LFC_LOGD_JFLUSH_REQD);
+ __gfs2_log_flush(sdp, NULL,
+ GFS2_LOG_HEAD_FLUSH_NORMAL |
+ GFS2_LFC_LOGD_JFLUSH_REQD);
+ up_write(&sdp->sd_log_flush_lock);
}
if (test_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags) ||
gfs2_ail_flush_reqd(sdp)) {
clear_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags);
+ down_write(&sdp->sd_log_flush_lock);
gfs2_ail1_start(sdp);
gfs2_ail1_wait(sdp);
gfs2_ail1_empty(sdp, 0);
- gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL |
- GFS2_LFC_LOGD_AIL_FLUSH_REQD);
+ __gfs2_log_flush(sdp, NULL,
+ GFS2_LOG_HEAD_FLUSH_NORMAL |
+ GFS2_LFC_LOGD_AIL_FLUSH_REQD);
+ up_write(&sdp->sd_log_flush_lock);
}
t = gfs2_tune_get(sdp, gt_logd_secs) * HZ;
diff --git a/fs/internal.h b/fs/internal.h
index 77e90e4124e0..8c1f6c548dbf 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -200,7 +200,6 @@ extern int build_open_flags(const struct open_how *how, struct open_flags *op);
struct file *file_close_fd_locked(struct files_struct *files, unsigned fd);
int do_ftruncate(struct file *file, loff_t length, int small);
-int do_sys_ftruncate(unsigned int fd, loff_t length, int small);
int chmod_common(const struct path *path, umode_t mode);
int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group,
int flag);
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 255a847ca0b6..abc65dc79f85 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -80,6 +80,11 @@ static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
return buf;
}
+#else
+static inline const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
+{
+ return "???";
+}
#endif
/*
diff --git a/fs/mbcache.c b/fs/mbcache.c
index 480d02d6ebf0..2a6319b4072c 100644
--- a/fs/mbcache.c
+++ b/fs/mbcache.c
@@ -406,6 +406,7 @@ void mb_cache_destroy(struct mb_cache *cache)
{
struct mb_cache_entry *entry, *next;
+ cancel_work_sync(&cache->c_shrink_work);
shrinker_free(cache->c_shrink);
/*
diff --git a/fs/netfs/iterator.c b/fs/netfs/iterator.c
index 154a14bb2d7f..429e4396e1b0 100644
--- a/fs/netfs/iterator.c
+++ b/fs/netfs/iterator.c
@@ -22,7 +22,7 @@
*
* Extract the page fragments from the given amount of the source iterator and
* build up a second iterator that refers to all of those bits. This allows
- * the original iterator to disposed of.
+ * the original iterator to be disposed of.
*
* @extraction_flags can have ITER_ALLOW_P2PDMA set to request peer-to-peer DMA be
* allowed on the pages extracted.
@@ -43,7 +43,7 @@ ssize_t netfs_extract_user_iter(struct iov_iter *orig, size_t orig_len,
unsigned int max_pages;
unsigned int npages = 0;
unsigned int i;
- ssize_t ret;
+ ssize_t ret = 0;
size_t count = orig_len, offset, len;
size_t bv_size, pg_size;
@@ -67,8 +67,8 @@ ssize_t netfs_extract_user_iter(struct iov_iter *orig, size_t orig_len,
ret = iov_iter_extract_pages(orig, &pages, count,
max_pages - npages, extraction_flags,
&offset);
- if (ret < 0) {
- pr_err("Couldn't get user pages (rc=%zd)\n", ret);
+ if (unlikely(ret <= 0)) {
+ ret = ret ?: -EIO;
break;
}
@@ -97,6 +97,13 @@ ssize_t netfs_extract_user_iter(struct iov_iter *orig, size_t orig_len,
npages += cur_npages;
}
+ if (ret < 0 && (ret == -ENOMEM || npages == 0)) {
+ for (i = 0; i < npages; i++)
+ unpin_user_page(bv[i].bv_page);
+ kvfree(bv);
+ return ret;
+ }
+
iov_iter_bvec(new, orig->data_source, bv, npages, orig_len - count);
return npages;
}
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c
index cb0a645aeb50..94e85ad9067e 100644
--- a/fs/nfs/blocklayout/blocklayout.c
+++ b/fs/nfs/blocklayout/blocklayout.c
@@ -381,14 +381,13 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync)
sector_t isect, extent_length = 0;
struct parallel_io *par = NULL;
loff_t offset = header->args.offset;
- size_t count = header->args.count;
struct page **pages = header->args.pages;
int pg_index = header->args.pgbase >> PAGE_SHIFT;
unsigned int pg_len;
struct blk_plug plug;
int i;
- dprintk("%s enter, %zu@%lld\n", __func__, count, offset);
+ dprintk("%s enter, %u@%lld\n", __func__, header->args.count, offset);
/* At this point, header->page_aray is a (sequential) list of nfs_pages.
* We want to write each, and if there is an error set pnfs_error
@@ -429,7 +428,6 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync)
}
offset += pg_len;
- count -= pg_len;
isect += (pg_len >> SECTOR_SHIFT);
extent_length -= (pg_len >> SECTOR_SHIFT);
}
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 6880c5c520e7..6b8f01129ecc 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1413,6 +1413,9 @@ nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
dst, clone->cl_dst_pos, clone->cl_count,
EX_ISSYNC(cstate->current_fh.fh_export));
+ if (!status && (READ_ONCE(dst->nf_file->f_mode) & FMODE_NOCMTIME) != 0)
+ nfsd_update_cmtime_attr(dst->nf_file, 0);
+
nfsd_file_put(dst);
nfsd_file_put(src);
out:
@@ -2118,8 +2121,10 @@ static int nfsd4_do_async_copy(void *data)
set_bit(NFSD4_COPY_F_COMPLETED, ©->cp_flags);
trace_nfsd_copy_async_done(copy);
- nfsd4_send_cb_offload(copy);
atomic_dec(©->cp_nn->pending_async_copies);
+ if (copy->cp_res.wr_bytes_written > 0 && copy->attr_update)
+ nfsd_update_cmtime_attr(copy->nf_dst->nf_file, 0);
+ nfsd4_send_cb_offload(copy);
return 0;
}
@@ -2179,6 +2184,9 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
memcpy(&result->cb_stateid, ©->cp_stateid.cs_stid,
sizeof(result->cb_stateid));
dup_copy_fields(copy, async_copy);
+ if ((READ_ONCE(copy->nf_dst->nf_file->f_mode) &
+ FMODE_NOCMTIME) != 0)
+ async_copy->attr_update = true;
memcpy(async_copy->cp_cb_offload.co_referring_sessionid.data,
cstate->session->se_sessionid.data,
NFS4_MAX_SESSIONID_LEN);
@@ -2197,6 +2205,10 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
} else {
status = nfsd4_do_copy(copy, copy->nf_src->nf_file,
copy->nf_dst->nf_file, true);
+ if ((READ_ONCE(copy->nf_dst->nf_file->f_mode) &
+ FMODE_NOCMTIME) != 0 &&
+ copy->cp_res.wr_bytes_written > 0)
+ nfsd_update_cmtime_attr(copy->nf_dst->nf_file, 0);
}
out:
trace_nfsd_copy_done(copy, status);
@@ -2535,10 +2547,6 @@ nfsd4_get_dir_delegation(struct svc_rqst *rqstp,
dd = nfsd_get_dir_deleg(cstate, gdd, nf);
nfsd_file_put(nf);
if (IS_ERR(dd)) {
- int err = PTR_ERR(dd);
-
- if (err != -EAGAIN)
- return nfserrno(err);
gdd->gddrnf_status = GDD4_UNAVAIL;
return nfs_ok;
}
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 6b9c399b89df..44b1a93f219a 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1226,10 +1226,6 @@ static void put_deleg_file(struct nfs4_file *fp)
static void nfsd4_finalize_deleg_timestamps(struct nfs4_delegation *dp, struct file *f)
{
- struct iattr ia = { .ia_valid = ATTR_ATIME | ATTR_CTIME | ATTR_MTIME | ATTR_DELEG };
- struct inode *inode = file_inode(f);
- int ret;
-
/* don't do anything if FMODE_NOCMTIME isn't set */
if ((READ_ONCE(f->f_mode) & FMODE_NOCMTIME) == 0)
return;
@@ -1247,17 +1243,7 @@ static void nfsd4_finalize_deleg_timestamps(struct nfs4_delegation *dp, struct f
return;
/* Stamp everything to "now" */
- inode_lock(inode);
- ret = notify_change(&nop_mnt_idmap, f->f_path.dentry, &ia, NULL);
- inode_unlock(inode);
- if (ret) {
- struct inode *inode = file_inode(f);
-
- pr_notice_ratelimited("nfsd: Unable to update timestamps on inode %02x:%02x:%lu: %d\n",
- MAJOR(inode->i_sb->s_dev),
- MINOR(inode->i_sb->s_dev),
- inode->i_ino, ret);
- }
+ nfsd_update_cmtime_attr(f, ATTR_ATIME);
}
static void nfs4_unlock_deleg_lease(struct nfs4_delegation *dp)
@@ -1495,8 +1481,24 @@ release_all_access(struct nfs4_ol_stateid *stp)
}
}
+/**
+ * nfs4_replay_free_cache - release dynamically allocated replay buffer
+ * @rp: replay cache to reset
+ *
+ * If @rp->rp_buf points to a kmalloc'd buffer, free it and reset
+ * rp_buf to the inline rp_ibuf. Always zeroes rp_buflen.
+ */
+void nfs4_replay_free_cache(struct nfs4_replay *rp)
+{
+ if (rp->rp_buf != rp->rp_ibuf)
+ kfree(rp->rp_buf);
+ rp->rp_buf = rp->rp_ibuf;
+ rp->rp_buflen = 0;
+}
+
static inline void nfs4_free_stateowner(struct nfs4_stateowner *sop)
{
+ nfs4_replay_free_cache(&sop->so_replay);
kfree(sop->so_owner.data);
sop->so_ops->so_free(sop);
}
@@ -6257,12 +6259,12 @@ nfsd4_add_rdaccess_to_wrdeleg(struct svc_rqst *rqstp, struct nfsd4_open *open,
return (false);
fp = stp->st_stid.sc_file;
spin_lock(&fp->fi_lock);
- __nfs4_file_get_access(fp, NFS4_SHARE_ACCESS_READ);
if (!fp->fi_fds[O_RDONLY]) {
+ __nfs4_file_get_access(fp, NFS4_SHARE_ACCESS_READ);
fp->fi_fds[O_RDONLY] = nf;
+ fp->fi_rdeleg_file = nfsd_file_get(fp->fi_fds[O_RDONLY]);
nf = NULL;
}
- fp->fi_rdeleg_file = nfsd_file_get(fp->fi_fds[O_RDONLY]);
spin_unlock(&fp->fi_lock);
if (nf)
nfsd_file_put(nf);
@@ -6352,7 +6354,6 @@ nfs4_open_delegation(struct svc_rqst *rqstp, struct nfsd4_open *open,
}
open->op_delegate_type = deleg_ts ? OPEN_DELEGATE_WRITE_ATTRS_DELEG :
OPEN_DELEGATE_WRITE;
- dp->dl_cb_fattr.ncf_cur_fsize = stat.size;
dp->dl_cb_fattr.ncf_initial_cinfo = nfsd4_change_attribute(&stat);
dp->dl_atime = stat.atime;
dp->dl_ctime = stat.ctime;
@@ -9401,11 +9402,15 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct dentry *dentry,
if (status != nfserr_jukebox ||
!nfsd_wait_for_delegreturn(rqstp, inode))
goto out_status;
+ status = nfs_ok;
+ goto out_status;
+ }
+ if (!ncf->ncf_file_modified) {
+ if (ncf->ncf_initial_cinfo != ncf->ncf_cb_change)
+ ncf->ncf_file_modified = true;
+ else if (i_size_read(inode) != ncf->ncf_cb_fsize)
+ ncf->ncf_file_modified = true;
}
- if (!ncf->ncf_file_modified &&
- (ncf->ncf_initial_cinfo != ncf->ncf_cb_change ||
- ncf->ncf_cur_fsize != ncf->ncf_cb_fsize))
- ncf->ncf_file_modified = true;
if (ncf->ncf_file_modified) {
int err;
@@ -9531,3 +9536,31 @@ nfsd_get_dir_deleg(struct nfsd4_compound_state *cstate,
put_nfs4_file(fp);
return ERR_PTR(status);
}
+
+/**
+ * nfsd_update_cmtime_attr - update file's delegated ctime/mtime,
+ * and optionally other attributes (ie ATTR_ATIME).
+ * @f: pointer to an opened file
+ * @flags: any additional flags that should be updated
+ *
+ * Given upon opening a file delegated attributes were issues, update
+ * @f attributes to current times.
+ */
+void nfsd_update_cmtime_attr(struct file *f, unsigned int flags)
+{
+ int ret;
+ struct inode *inode = file_inode(f);
+ struct iattr attr = {
+ .ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_DELEG | flags,
+ };
+
+ inode_lock(inode);
+ ret = notify_change(&nop_mnt_idmap, f->f_path.dentry, &attr, NULL);
+ inode_unlock(inode);
+ if (ret)
+ pr_notice_ratelimited("nfsd: Unable to update timestamps on "
+ "inode %02x:%02x:%lu: %d\n",
+ MAJOR(inode->i_sb->s_dev),
+ MINOR(inode->i_sb->s_dev),
+ inode->i_ino, ret);
+}
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 9d234913100b..ef663331063b 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -6281,14 +6281,23 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
int len = xdr->buf->len - (op_status_offset + XDR_UNIT);
so->so_replay.rp_status = op->status;
- if (len <= NFSD4_REPLAY_ISIZE) {
- so->so_replay.rp_buflen = len;
- read_bytes_from_xdr_buf(xdr->buf,
- op_status_offset + XDR_UNIT,
- so->so_replay.rp_buf, len);
- } else {
- so->so_replay.rp_buflen = 0;
+ if (len > NFSD4_REPLAY_ISIZE) {
+ char *buf = kmalloc(len, GFP_KERNEL);
+
+ nfs4_replay_free_cache(&so->so_replay);
+ if (buf) {
+ so->so_replay.rp_buf = buf;
+ } else {
+ /* rp_buflen already zeroed; skip caching */
+ goto status;
+ }
+ } else if (so->so_replay.rp_buf != so->so_replay.rp_ibuf) {
+ nfs4_replay_free_cache(&so->so_replay);
}
+ so->so_replay.rp_buflen = len;
+ read_bytes_from_xdr_buf(xdr->buf,
+ op_status_offset + XDR_UNIT,
+ so->so_replay.rp_buf, len);
}
status:
op->status = nfsd4_map_status(op->status,
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index ed85dd43da18..68b629fbaaeb 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -105,9 +105,12 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp,
{
/* Check if the request originated from a secure port. */
if (rqstp && !nfsd_originating_port_ok(rqstp, cred, exp)) {
- RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
- dprintk("nfsd: request from insecure port %s!\n",
- svc_print_addr(rqstp, buf, sizeof(buf)));
+ if (IS_ENABLED(CONFIG_SUNRPC_DEBUG)) {
+ char buf[RPC_MAX_ADDRBUFLEN];
+
+ dprintk("nfsd: request from insecure port %s!\n",
+ svc_print_addr(rqstp, buf, sizeof(buf)));
+ }
return nfserr_perm;
}
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index c0ca115c3b74..5afee1342aa9 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -549,10 +549,10 @@ struct nfs4_client_reclaim {
* ~32(deleg. ace) = 112 bytes
*
* Some responses can exceed this. A LOCK denial includes the conflicting
- * lock owner, which can be up to 1024 bytes (NFS4_OPAQUE_LIMIT). Responses
- * larger than REPLAY_ISIZE are not cached in rp_ibuf; only rp_status is
- * saved. Enlarging this constant increases the size of every
- * nfs4_stateowner.
+ * lock owner, which can be up to 1024 bytes (NFS4_OPAQUE_LIMIT). When a
+ * response exceeds REPLAY_ISIZE, a buffer is dynamically allocated. If
+ * that allocation fails, only rp_status is saved. Enlarging this constant
+ * increases the size of every nfs4_stateowner.
*/
#define NFSD4_REPLAY_ISIZE 112
@@ -564,12 +564,14 @@ struct nfs4_client_reclaim {
struct nfs4_replay {
__be32 rp_status;
unsigned int rp_buflen;
- char *rp_buf;
+ char *rp_buf; /* rp_ibuf or kmalloc'd */
struct knfsd_fh rp_openfh;
int rp_locked;
char rp_ibuf[NFSD4_REPLAY_ISIZE];
};
+extern void nfs4_replay_free_cache(struct nfs4_replay *rp);
+
struct nfs4_stateowner;
struct nfs4_stateowner_operations {
@@ -832,6 +834,7 @@ extern void nfsd4_shutdown_copy(struct nfs4_client *clp);
void nfsd4_put_client(struct nfs4_client *clp);
void nfsd4_async_copy_reaper(struct nfsd_net *nn);
bool nfsd4_has_active_async_copies(struct nfs4_client *clp);
+void nfsd_update_cmtime_attr(struct file *f, unsigned int flags);
extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name,
struct xdr_netobj princhash, struct nfsd_net *nn);
extern bool nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn);
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 417e9ad9fbb3..9a4124c77e04 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -752,6 +752,7 @@ struct nfsd4_copy {
struct nfsd_file *nf_src;
struct nfsd_file *nf_dst;
+ bool attr_update;
copy_stateid_t cp_stateid;
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c
index e17b8da66491..e0a606643e87 100644
--- a/fs/nilfs2/ioctl.c
+++ b/fs/nilfs2/ioctl.c
@@ -736,6 +736,12 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs,
int ret, i;
for (i = 0; i < nmembs; i++) {
+ /*
+ * bd_oblocknr must never be 0 as block 0
+ * is never a valid GC target block
+ */
+ if (unlikely(!bdescs[i].bd_oblocknr))
+ return -EINVAL;
/* XXX: use macro or inline func to check liveness */
ret = nilfs_bmap_lookup_at_level(bmap,
bdescs[i].bd_offset,
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index c2dcb25151de..ae904451dfc0 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -1210,6 +1210,7 @@ static int fanotify_find_path(int dfd, const char __user *filename,
*path = fd_file(f)->f_path;
path_get(path);
+ ret = 0;
} else {
unsigned int lookup_flags = 0;
@@ -1219,22 +1220,7 @@ static int fanotify_find_path(int dfd, const char __user *filename,
lookup_flags |= LOOKUP_DIRECTORY;
ret = user_path_at(dfd, filename, lookup_flags, path);
- if (ret)
- goto out;
- }
-
- /* you can only watch an inode if you have read permissions on it */
- ret = path_permission(path, MAY_READ);
- if (ret) {
- path_put(path);
- goto out;
}
-
- ret = security_path_notify(path, mask, obj_type);
- if (ret)
- path_put(path);
-
-out:
return ret;
}
@@ -1615,17 +1601,18 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
pr_debug("%s: flags=%x event_f_flags=%x\n",
__func__, flags, event_f_flags);
- if (!capable(CAP_SYS_ADMIN)) {
- /*
- * An unprivileged user can setup an fanotify group with
- * limited functionality - an unprivileged group is limited to
- * notification events with file handles or mount ids and it
- * cannot use unlimited queue/marks.
- */
- if ((flags & FANOTIFY_ADMIN_INIT_FLAGS) ||
- !(flags & (FANOTIFY_FID_BITS | FAN_REPORT_MNT)))
- return -EPERM;
+ /*
+ * An unprivileged user can setup an fanotify group with limited
+ * functionality - an unprivileged group is limited to notification
+ * events with file handles or mount ids and it cannot use unlimited
+ * queue/marks.
+ */
+ if (((flags & FANOTIFY_ADMIN_INIT_FLAGS) ||
+ !(flags & (FANOTIFY_FID_BITS | FAN_REPORT_MNT))) &&
+ !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (!ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN)) {
/*
* Setting the internal flag FANOTIFY_UNPRIV on the group
* prevents setting mount/filesystem marks on this group and
@@ -1990,8 +1977,8 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
* A user is allowed to setup sb/mount/mntns marks only if it is
* capable in the user ns where the group was created.
*/
- if (!ns_capable(group->user_ns, CAP_SYS_ADMIN) &&
- mark_type != FAN_MARK_INODE)
+ if (mark_type != FAN_MARK_INODE &&
+ !ns_capable(group->user_ns, CAP_SYS_ADMIN))
return -EPERM;
/*
@@ -2057,6 +2044,15 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
goto path_put_and_out;
}
+ /* you can only watch an inode if you have read permissions on it */
+ ret = path_permission(&path, MAY_READ);
+ if (ret)
+ goto path_put_and_out;
+
+ ret = security_path_notify(&path, mask, obj_type);
+ if (ret)
+ goto path_put_and_out;
+
if (fid_mode) {
ret = fanotify_test_fsid(path.dentry, flags, &__fsid);
if (ret)
diff --git a/fs/notify/mark.c b/fs/notify/mark.c
index 622f05977f86..e256b420100d 100644
--- a/fs/notify/mark.c
+++ b/fs/notify/mark.c
@@ -238,7 +238,12 @@ static struct inode *fsnotify_update_iref(struct fsnotify_mark_connector *conn,
return inode;
}
-static void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
+/*
+ * Calculate mask of events for a list of marks.
+ *
+ * Return true if any of the attached marks want to hold an inode reference.
+ */
+static bool __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
{
u32 new_mask = 0;
bool want_iref = false;
@@ -262,6 +267,34 @@ static void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
*/
WRITE_ONCE(*fsnotify_conn_mask_p(conn), new_mask);
+ return want_iref;
+}
+
+/*
+ * Calculate mask of events for a list of marks after attach/modify mark
+ * and get an inode reference for the connector if needed.
+ *
+ * A concurrent add of evictable mark and detach of non-evictable mark can
+ * lead to __fsnotify_recalc_mask() returning false want_iref, but in this
+ * case we defer clearing iref to fsnotify_recalc_mask_clear_iref() called
+ * from fsnotify_put_mark().
+ */
+static void fsnotify_recalc_mask_set_iref(struct fsnotify_mark_connector *conn)
+{
+ bool has_iref = conn->flags & FSNOTIFY_CONN_FLAG_HAS_IREF;
+ bool want_iref = __fsnotify_recalc_mask(conn) || has_iref;
+
+ (void) fsnotify_update_iref(conn, want_iref);
+}
+
+/*
+ * Calculate mask of events for a list of marks after detach mark
+ * and return the inode object if its reference is no longer needed.
+ */
+static void *fsnotify_recalc_mask_clear_iref(struct fsnotify_mark_connector *conn)
+{
+ bool want_iref = __fsnotify_recalc_mask(conn);
+
return fsnotify_update_iref(conn, want_iref);
}
@@ -298,7 +331,7 @@ void fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
spin_lock(&conn->lock);
update_children = !fsnotify_conn_watches_children(conn);
- __fsnotify_recalc_mask(conn);
+ fsnotify_recalc_mask_set_iref(conn);
update_children &= fsnotify_conn_watches_children(conn);
spin_unlock(&conn->lock);
/*
@@ -419,7 +452,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark)
/* Update watched objects after detaching mark */
if (sb)
fsnotify_update_sb_watchers(sb, conn);
- objp = __fsnotify_recalc_mask(conn);
+ objp = fsnotify_recalc_mask_clear_iref(conn);
type = conn->type;
}
WRITE_ONCE(mark->connector, NULL);
diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c
index 6cb9bc5d605c..76e581d3961d 100644
--- a/fs/ntfs3/attrib.c
+++ b/fs/ntfs3/attrib.c
@@ -1152,6 +1152,21 @@ int attr_data_get_block_locked(struct ntfs_inode *ni, CLST vcn, CLST clen,
if (err)
goto out;
}
+
+ if (vcn0 < svcn || evcn1 <= vcn0) {
+ struct ATTRIB *attr2;
+
+ attr2 = ni_find_attr(ni, attr_b, &le_b, ATTR_DATA, NULL,
+ 0, &vcn0, &mi);
+ if (!attr2) {
+ err = -EINVAL;
+ goto out;
+ }
+ err = attr_load_runs(attr2, ni, run, NULL);
+ if (err)
+ goto out;
+ }
+
da = false; /* no delalloc for compressed file. */
}
diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c
index 6e65066ebcc1..eac421cf98a8 100644
--- a/fs/ntfs3/inode.c
+++ b/fs/ntfs3/inode.c
@@ -822,6 +822,11 @@ static int ntfs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
return err;
}
+ if (!clen) {
+ /* broken file? */
+ return -EINVAL;
+ }
+
if (lcn == EOF_LCN) {
/* request out of file. */
if (flags & IOMAP_REPORT) {
@@ -855,11 +860,6 @@ static int ntfs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
return 0;
}
- if (!clen) {
- /* broken file? */
- return -EINVAL;
- }
-
iomap->bdev = inode->i_sb->s_bdev;
iomap->offset = offset;
iomap->length = ((loff_t)clen << cluster_bits) - off;
diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c
index 174a7cb202a0..9ed485f9efba 100644
--- a/fs/ntfs3/super.c
+++ b/fs/ntfs3/super.c
@@ -1339,8 +1339,13 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
le32_to_cpu(attr->res.data_size) >> 1,
UTF16_LITTLE_ENDIAN, sbi->volume.label,
sizeof(sbi->volume.label));
- if (err < 0)
+ if (err < 0) {
sbi->volume.label[0] = 0;
+ } else if (err >= sizeof(sbi->volume.label)) {
+ sbi->volume.label[sizeof(sbi->volume.label) - 1] = 0;
+ } else {
+ sbi->volume.label[err] = 0;
+ }
} else {
/* Should we break mounting here? */
//err = -EINVAL;
diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c
index 70ca79e4bdc3..dc9da9133c8e 100644
--- a/fs/ocfs2/dlm/dlmdomain.c
+++ b/fs/ocfs2/dlm/dlmdomain.c
@@ -980,6 +980,14 @@ static int dlm_match_regions(struct dlm_ctxt *dlm,
goto bail;
}
+ if (qr->qr_numregions > O2NM_MAX_REGIONS) {
+ mlog(ML_ERROR, "Domain %s: Joining node %d has invalid "
+ "number of heartbeat regions %u\n",
+ qr->qr_domain, qr->qr_node, qr->qr_numregions);
+ status = -EINVAL;
+ goto bail;
+ }
+
r = remote;
for (i = 0; i < qr->qr_numregions; ++i) {
mlog(0, "Region %.*s\n", O2HB_MAX_REGION_NAME_LEN, r);
@@ -994,7 +1002,7 @@ static int dlm_match_regions(struct dlm_ctxt *dlm,
for (i = 0; i < localnr; ++i) {
foundit = 0;
r = remote;
- for (j = 0; j <= qr->qr_numregions; ++j) {
+ for (j = 0; j < qr->qr_numregions; ++j) {
if (!memcmp(l, r, O2HB_MAX_REGION_NAME_LEN)) {
foundit = 1;
break;
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
index bfed0fb35f9b..cbe59d231666 100644
--- a/fs/ocfs2/ioctl.c
+++ b/fs/ocfs2/ioctl.c
@@ -441,13 +441,16 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb,
struct buffer_head *bh = NULL;
struct ocfs2_group_desc *bg = NULL;
- unsigned int max_bits, num_clusters;
+ unsigned int max_bits, max_bitmap_bits, num_clusters;
unsigned int offset = 0, cluster, chunk;
unsigned int chunk_free, last_chunksize = 0;
if (!le32_to_cpu(rec->c_free))
goto bail;
+ max_bitmap_bits = 8 * ocfs2_group_bitmap_size(osb->sb, 0,
+ osb->s_feature_incompat);
+
do {
if (!bg)
blkno = le64_to_cpu(rec->c_blkno);
@@ -479,6 +482,19 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb,
continue;
max_bits = le16_to_cpu(bg->bg_bits);
+
+ /*
+ * Non-coherent scans read raw blocks and do not get the
+ * bg_bits validation from
+ * ocfs2_read_group_descriptor().
+ */
+ if (max_bits > max_bitmap_bits) {
+ mlog(ML_ERROR,
+ "Group desc #%llu has %u bits, max bitmap bits %u\n",
+ (unsigned long long)blkno, max_bits, max_bitmap_bits);
+ max_bits = max_bitmap_bits;
+ }
+
offset = 0;
for (chunk = 0; chunk < chunks_in_group; chunk++) {
diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c
index 09724e7dc01b..6375d5035972 100644
--- a/fs/ocfs2/resize.c
+++ b/fs/ocfs2/resize.c
@@ -508,14 +508,14 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input)
goto out_unlock;
}
- ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), group_bh);
-
ret = ocfs2_verify_group_and_input(main_bm_inode, fe, input, group_bh);
if (ret) {
mlog_errno(ret);
goto out_free_group_bh;
}
+ ocfs2_set_new_buffer_uptodate(INODE_CACHE(main_bm_inode), group_bh);
+
trace_ocfs2_group_add((unsigned long long)input->group,
input->chain, input->clusters, input->frees);
@@ -523,7 +523,7 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input)
if (IS_ERR(handle)) {
mlog_errno(PTR_ERR(handle));
ret = -EINVAL;
- goto out_free_group_bh;
+ goto out_remove_cache;
}
cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc);
@@ -577,9 +577,11 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input)
out_commit:
ocfs2_commit_trans(osb, handle);
-out_free_group_bh:
+out_remove_cache:
if (ret < 0)
- ocfs2_remove_from_cache(INODE_CACHE(inode), group_bh);
+ ocfs2_remove_from_cache(INODE_CACHE(main_bm_inode), group_bh);
+
+out_free_group_bh:
brelse(group_bh);
out_unlock:
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
index 42ee5db362d3..b9a6bdbf596c 100644
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -911,8 +911,8 @@ static int ocfs2_xattr_list_entry(struct super_block *sb,
total_len = prefix_len + name_len + 1;
*result += total_len;
- /* we are just looking for how big our buffer needs to be */
- if (!size)
+ /* No buffer means we are only looking for the required size. */
+ if (!buffer)
return 0;
if (*result > size)
diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c
index 90ae07c69349..834cae1e6223 100644
--- a/fs/omfs/inode.c
+++ b/fs/omfs/inode.c
@@ -513,6 +513,12 @@ static int omfs_fill_super(struct super_block *sb, struct fs_context *fc)
goto out_brelse_bh;
}
+ if (sbi->s_sys_blocksize < OMFS_DIR_START) {
+ printk(KERN_ERR "omfs: sysblock size (%d) is too small\n",
+ sbi->s_sys_blocksize);
+ goto out_brelse_bh;
+ }
+
if (sbi->s_blocksize < sbi->s_sys_blocksize ||
sbi->s_blocksize > OMFS_MAX_BLOCK_SIZE) {
printk(KERN_ERR "omfs: block size (%d) is out of range\n",
diff --git a/fs/open.c b/fs/open.c
index 91f1139591ab..412d0d6fbaa7 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -197,7 +197,7 @@ int do_ftruncate(struct file *file, loff_t length, int small)
ATTR_MTIME | ATTR_CTIME, file);
}
-int do_sys_ftruncate(unsigned int fd, loff_t length, int small)
+int ksys_ftruncate(unsigned int fd, loff_t length, unsigned int flags)
{
if (length < 0)
return -EINVAL;
@@ -205,18 +205,18 @@ int do_sys_ftruncate(unsigned int fd, loff_t length, int small)
if (fd_empty(f))
return -EBADF;
- return do_ftruncate(fd_file(f), length, small);
+ return do_ftruncate(fd_file(f), length, !(flags & FTRUNCATE_LFS));
}
SYSCALL_DEFINE2(ftruncate, unsigned int, fd, off_t, length)
{
- return do_sys_ftruncate(fd, length, 1);
+ return ksys_ftruncate(fd, length, 0);
}
#ifdef CONFIG_COMPAT
COMPAT_SYSCALL_DEFINE2(ftruncate, unsigned int, fd, compat_off_t, length)
{
- return do_sys_ftruncate(fd, length, 1);
+ return ksys_ftruncate(fd, length, 0);
}
#endif
@@ -229,7 +229,7 @@ SYSCALL_DEFINE2(truncate64, const char __user *, path, loff_t, length)
SYSCALL_DEFINE2(ftruncate64, unsigned int, fd, loff_t, length)
{
- return do_sys_ftruncate(fd, length, 0);
+ return ksys_ftruncate(fd, length, FTRUNCATE_LFS);
}
#endif /* BITS_PER_LONG == 32 */
@@ -245,7 +245,7 @@ COMPAT_SYSCALL_DEFINE3(truncate64, const char __user *, pathname,
COMPAT_SYSCALL_DEFINE3(ftruncate64, unsigned int, fd,
compat_arg_u64_dual(length))
{
- return ksys_ftruncate(fd, compat_arg_u64_glue(length));
+ return ksys_ftruncate(fd, compat_arg_u64_glue(length), FTRUNCATE_LFS);
}
#endif
diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c
index ed97494abf60..0713ef986c20 100644
--- a/fs/pstore/ram_core.c
+++ b/fs/pstore/ram_core.c
@@ -488,6 +488,10 @@ static void *persistent_ram_iomap(phys_addr_t start, size_t size,
else
va = ioremap_wc(start, size);
+ /* We must release the mem region if ioremap fails. */
+ if (!va)
+ release_mem_region(start, size);
+
/*
* Since request_mem_region() and ioremap() are byte-granularity
* there is no need handle anything special like we do when the
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 376739f6420e..64cf42721496 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -363,6 +363,31 @@ static inline int dquot_active(struct dquot *dquot)
return test_bit(DQ_ACTIVE_B, &dquot->dq_flags);
}
+static struct dquot *__dqgrab(struct dquot *dquot)
+{
+ lockdep_assert_held(&dq_list_lock);
+ if (!atomic_read(&dquot->dq_count))
+ remove_free_dquot(dquot);
+ atomic_inc(&dquot->dq_count);
+ return dquot;
+}
+
+/*
+ * Get reference to dquot when we got pointer to it by some other means. The
+ * dquot has to be active and the caller has to make sure it cannot get
+ * deactivated under our hands.
+ */
+struct dquot *dqgrab(struct dquot *dquot)
+{
+ spin_lock(&dq_list_lock);
+ WARN_ON_ONCE(!dquot_active(dquot));
+ dquot = __dqgrab(dquot);
+ spin_unlock(&dq_list_lock);
+
+ return dquot;
+}
+EXPORT_SYMBOL_GPL(dqgrab);
+
static inline int dquot_dirty(struct dquot *dquot)
{
return test_bit(DQ_MOD_B, &dquot->dq_flags);
@@ -641,15 +666,14 @@ int dquot_scan_active(struct super_block *sb,
continue;
if (dquot->dq_sb != sb)
continue;
- /* Now we have active dquot so we can just increase use count */
- atomic_inc(&dquot->dq_count);
+ __dqgrab(dquot);
spin_unlock(&dq_list_lock);
dqput(old_dquot);
old_dquot = dquot;
/*
* ->release_dquot() can be racing with us. Our reference
- * protects us from new calls to it so just wait for any
- * outstanding call and recheck the DQ_ACTIVE_B after that.
+ * protects us from dquot_release() proceeding so just wait for
+ * any outstanding call and recheck the DQ_ACTIVE_B after that.
*/
wait_on_dquot(dquot);
if (dquot_active(dquot)) {
@@ -717,7 +741,7 @@ int dquot_writeback_dquots(struct super_block *sb, int type)
/* Now we have active dquot from which someone is
* holding reference so we can safely just increase
* use count */
- dqgrab(dquot);
+ __dqgrab(dquot);
spin_unlock(&dq_list_lock);
err = dquot_write_dquot(dquot);
if (err && !ret)
@@ -963,9 +987,7 @@ struct dquot *dqget(struct super_block *sb, struct kqid qid)
spin_unlock(&dq_list_lock);
dqstats_inc(DQST_LOOKUPS);
} else {
- if (!atomic_read(&dquot->dq_count))
- remove_free_dquot(dquot);
- atomic_inc(&dquot->dq_count);
+ __dqgrab(dquot);
spin_unlock(&dq_list_lock);
dqstats_inc(DQST_CACHE_HITS);
dqstats_inc(DQST_LOOKUPS);
diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c
index cc4237c57cbe..2ef53161ce11 100644
--- a/fs/resctrl/ctrlmondata.c
+++ b/fs/resctrl/ctrlmondata.c
@@ -992,6 +992,7 @@ static int resctrl_io_alloc_parse_line(char *line, struct rdt_resource *r,
}
}
+ rdt_last_cmd_printf("Invalid domain %lu\n", dom_id);
return -EINVAL;
}
diff --git a/fs/smb/client/ioctl.c b/fs/smb/client/ioctl.c
index 9afab3237e54..17408bb8ab65 100644
--- a/fs/smb/client/ioctl.c
+++ b/fs/smb/client/ioctl.c
@@ -296,7 +296,7 @@ static int cifs_dump_full_key(struct cifs_tcon *tcon, struct smb3_full_key_debug
break;
case SMB2_ENCRYPTION_AES256_CCM:
case SMB2_ENCRYPTION_AES256_GCM:
- out.session_key_length = CIFS_SESS_KEY_SIZE;
+ out.session_key_length = ses->auth_key.len;
out.server_in_key_length = out.server_out_key_length = SMB3_GCM256_CRYPTKEY_SIZE;
break;
default:
diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c
index b292aa94a593..6860eff31693 100644
--- a/fs/smb/client/smb2file.c
+++ b/fs/smb/client/smb2file.c
@@ -49,6 +49,9 @@ static struct smb2_symlink_err_rsp *symlink_data(const struct kvec *iov)
__func__, le32_to_cpu(p->ErrorId));
len = ALIGN(le32_to_cpu(p->ErrorDataLength), 8);
+ if (len > end - ((u8 *)p + sizeof(*p)))
+ return ERR_PTR(-EINVAL);
+
p = (struct smb2_error_context_rsp *)(p->ErrorContextData + len);
}
} else if (le32_to_cpu(err->ByteCount) >= sizeof(*sym) &&
diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index 81be2b226e26..bcd7ec9c9521 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -259,7 +259,8 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
}
static int generate_key(struct cifs_ses *ses, struct kvec label,
- struct kvec context, __u8 *key, unsigned int key_size)
+ struct kvec context, __u8 *key, unsigned int key_size,
+ unsigned int full_key_size)
{
unsigned char zero = 0x0;
__u8 i[4] = {0, 0, 0, 1};
@@ -280,7 +281,7 @@ static int generate_key(struct cifs_ses *ses, struct kvec label,
}
hmac_sha256_init_usingrawkey(&hmac_ctx, ses->auth_key.response,
- SMB2_NTLMV2_SESSKEY_SIZE);
+ full_key_size);
hmac_sha256_update(&hmac_ctx, i, 4);
hmac_sha256_update(&hmac_ctx, label.iov_base, label.iov_len);
hmac_sha256_update(&hmac_ctx, &zero, 1);
@@ -314,6 +315,7 @@ generate_smb3signingkey(struct cifs_ses *ses,
struct TCP_Server_Info *server,
const struct derivation_triplet *ptriplet)
{
+ unsigned int full_key_size = SMB2_NTLMV2_SESSKEY_SIZE;
int rc;
bool is_binding = false;
int chan_index = 0;
@@ -348,17 +350,31 @@ generate_smb3signingkey(struct cifs_ses *ses,
rc = generate_key(ses, ptriplet->signing.label,
ptriplet->signing.context,
ses->chans[chan_index].signkey,
- SMB3_SIGN_KEY_SIZE);
+ SMB3_SIGN_KEY_SIZE,
+ SMB2_NTLMV2_SESSKEY_SIZE);
if (rc)
return rc;
} else {
rc = generate_key(ses, ptriplet->signing.label,
ptriplet->signing.context,
ses->smb3signingkey,
- SMB3_SIGN_KEY_SIZE);
+ SMB3_SIGN_KEY_SIZE,
+ SMB2_NTLMV2_SESSKEY_SIZE);
if (rc)
return rc;
+ /*
+ * Per MS-SMB2 3.2.5.3.1, signing key always uses Session.SessionKey
+ * (first 16 bytes). Encryption/decryption keys use
+ * Session.FullSessionKey when dialect is 3.1.1 and cipher is
+ * AES-256-CCM or AES-256-GCM, otherwise Session.SessionKey.
+ */
+
+ if (server->dialect == SMB311_PROT_ID &&
+ (server->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
+ server->cipher_type == SMB2_ENCRYPTION_AES256_GCM))
+ full_key_size = ses->auth_key.len;
+
/* safe to access primary channel, since it will never go away */
spin_lock(&ses->chan_lock);
memcpy(ses->chans[chan_index].signkey, ses->smb3signingkey,
@@ -368,13 +384,15 @@ generate_smb3signingkey(struct cifs_ses *ses,
rc = generate_key(ses, ptriplet->encryption.label,
ptriplet->encryption.context,
ses->smb3encryptionkey,
- SMB3_ENC_DEC_KEY_SIZE);
+ SMB3_ENC_DEC_KEY_SIZE,
+ full_key_size);
if (rc)
return rc;
rc = generate_key(ses, ptriplet->decryption.label,
ptriplet->decryption.context,
ses->smb3decryptionkey,
- SMB3_ENC_DEC_KEY_SIZE);
+ SMB3_ENC_DEC_KEY_SIZE,
+ full_key_size);
if (rc)
return rc;
}
@@ -389,7 +407,7 @@ generate_smb3signingkey(struct cifs_ses *ses,
&ses->Suid);
cifs_dbg(VFS, "Cipher type %d\n", server->cipher_type);
cifs_dbg(VFS, "Session Key %*ph\n",
- SMB2_NTLMV2_SESSKEY_SIZE, ses->auth_key.response);
+ (int)ses->auth_key.len, ses->auth_key.response);
cifs_dbg(VFS, "Signing Key %*ph\n",
SMB3_SIGN_KEY_SIZE, ses->smb3signingkey);
if ((server->cipher_type == SMB2_ENCRYPTION_AES256_CCM) ||
diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c
index af5f40304331..7d0691f7263f 100644
--- a/fs/smb/server/auth.c
+++ b/fs/smb/server/auth.c
@@ -827,6 +827,7 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov,
struct smb2_transform_hdr *tr_hdr = smb_get_msg(iov[0].iov_base);
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
int rc;
+ DECLARE_CRYPTO_WAIT(wait);
struct scatterlist *sg;
u8 sign[SMB2_SIGNATURE_SIZE] = {};
u8 key[SMB3_ENC_DEC_KEY_SIZE];
@@ -913,12 +914,12 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov,
aead_request_set_crypt(req, sg, sg, crypt_len, iv);
aead_request_set_ad(req, assoc_data_len);
- aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
+ aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
+ CRYPTO_TFM_REQ_MAY_SLEEP,
+ crypto_req_done, &wait);
- if (enc)
- rc = crypto_aead_encrypt(req);
- else
- rc = crypto_aead_decrypt(req);
+ rc = crypto_wait_req(enc ? crypto_aead_encrypt(req) :
+ crypto_aead_decrypt(req), &wait);
if (rc)
goto free_iv;
diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c
index 9d7e8a081272..fb9918e5d987 100644
--- a/fs/smb/server/connection.c
+++ b/fs/smb/server/connection.c
@@ -98,6 +98,15 @@ void ksmbd_conn_free(struct ksmbd_conn *conn)
kfree(conn->preauth_info);
kfree(conn->mechToken);
if (atomic_dec_and_test(&conn->refcnt)) {
+ /*
+ * async_ida is embedded in struct ksmbd_conn, so pair
+ * ida_destroy() with the final kfree() rather than with
+ * the unconditional field teardown above. This keeps
+ * the IDA valid for the entire lifetime of the struct,
+ * even while other refcount holders (oplock / vfs
+ * durable handles) still reference the connection.
+ */
+ ida_destroy(&conn->async_ida);
conn->transport->ops->free_transport(conn->transport);
kfree(conn);
}
diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c
index a86589408835..de58aed76cb4 100644
--- a/fs/smb/server/mgmt/user_session.c
+++ b/fs/smb/server/mgmt/user_session.c
@@ -391,6 +391,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)
free_channel_list(sess);
kfree(sess->Preauth_HashValue);
ksmbd_release_id(&session_ida, sess->id);
+ ida_destroy(&sess->tree_conn_ida);
kfree(sess);
}
@@ -547,8 +548,13 @@ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
struct ksmbd_session *sess;
sess = ksmbd_session_lookup(conn, id);
- if (!sess && conn->binding)
+ if (!sess && conn->binding) {
sess = ksmbd_session_lookup_slowpath(id);
+ if (sess && !xa_load(&sess->ksmbd_chann_list, (long)conn)) {
+ ksmbd_user_session_put(sess);
+ sess = NULL;
+ }
+ }
if (sess && sess->state != SMB2_SESSION_VALID) {
ksmbd_user_session_put(sess);
sess = NULL;
@@ -665,6 +671,8 @@ static struct ksmbd_session *__session_create(int protocol)
if (!sess)
return NULL;
+ ida_init(&sess->tree_conn_ida);
+
if (ksmbd_init_file_table(&sess->file_table))
goto error;
@@ -684,8 +692,6 @@ static struct ksmbd_session *__session_create(int protocol)
if (ret)
goto error;
- ida_init(&sess->tree_conn_ida);
-
down_write(&sessions_table_lock);
hash_add(sessions_table, &sess->hlist, sess->id);
up_write(&sessions_table_lock);
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 135c74e6c4be..c3c7688f0fa8 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -2845,6 +2845,8 @@ static int parse_durable_handle_context(struct ksmbd_work *work,
dh_info->reconnected = true;
goto out;
}
+ ksmbd_put_durable_fd(dh_info->fp);
+ dh_info->fp = NULL;
}
if ((lc && (lc->req_state & SMB2_LEASE_HANDLE_CACHING_LE)) ||
@@ -3015,29 +3017,23 @@ int smb2_open(struct ksmbd_work *work)
if (dh_info.reconnected == true) {
rc = smb2_check_durable_oplock(conn, share, dh_info.fp,
lc, sess->user, name);
- if (rc) {
- ksmbd_put_durable_fd(dh_info.fp);
+ if (rc)
goto err_out2;
- }
rc = ksmbd_reopen_durable_fd(work, dh_info.fp);
- if (rc) {
- ksmbd_put_durable_fd(dh_info.fp);
+ if (rc)
goto err_out2;
- }
fp = dh_info.fp;
if (ksmbd_override_fsids(work)) {
rc = -ENOMEM;
- ksmbd_put_durable_fd(dh_info.fp);
goto err_out2;
}
file_info = FILE_OPENED;
rc = ksmbd_vfs_getattr(&fp->filp->f_path, &stat);
- ksmbd_put_durable_fd(fp);
if (rc)
goto err_out2;
@@ -3807,6 +3803,9 @@ int smb2_open(struct ksmbd_work *work)
ksmbd_debug(SMB, "Error response: %x\n", rsp->hdr.Status);
}
+ if (dh_info.reconnected)
+ ksmbd_put_durable_fd(dh_info.fp);
+
kfree(name);
kfree(lc);
diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c
index af3387eebef5..26b6453de30e 100644
--- a/fs/tracefs/event_inode.c
+++ b/fs/tracefs/event_inode.c
@@ -180,29 +180,25 @@ static int eventfs_set_attr(struct mnt_idmap *idmap, struct dentry *dentry,
const char *name;
int ret;
- mutex_lock(&eventfs_mutex);
+ guard(mutex)(&eventfs_mutex);
ei = dentry->d_fsdata;
- if (ei->is_freed) {
- /* Do not allow changes if the event is about to be removed. */
- mutex_unlock(&eventfs_mutex);
+ /* Do not allow changes if the event is about to be removed. */
+ if (ei->is_freed)
return -ENODEV;
- }
/* Preallocate the children mode array if necessary */
if (!(dentry->d_inode->i_mode & S_IFDIR)) {
if (!ei->entry_attrs) {
ei->entry_attrs = kzalloc_objs(*ei->entry_attrs,
ei->nr_entries, GFP_NOFS);
- if (!ei->entry_attrs) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!ei->entry_attrs)
+ return -ENOMEM;
}
}
ret = simple_setattr(idmap, dentry, iattr);
if (ret < 0)
- goto out;
+ return ret;
/*
* If this is a dir, then update the ei cache, only the file
@@ -225,8 +221,6 @@ static int eventfs_set_attr(struct mnt_idmap *idmap, struct dentry *dentry,
}
}
}
- out:
- mutex_unlock(&eventfs_mutex);
return ret;
}
@@ -530,26 +524,24 @@ static struct dentry *eventfs_root_lookup(struct inode *dir,
struct tracefs_inode *ti;
struct eventfs_inode *ei;
const char *name = dentry->d_name.name;
- struct dentry *result = NULL;
ti = get_tracefs(dir);
if (WARN_ON_ONCE(!(ti->flags & TRACEFS_EVENT_INODE)))
return ERR_PTR(-EIO);
- mutex_lock(&eventfs_mutex);
+ guard(mutex)(&eventfs_mutex);
ei = ti->private;
if (!ei || ei->is_freed)
- goto out;
+ return NULL;
list_for_each_entry(ei_child, &ei->children, list) {
if (strcmp(ei_child->name, name) != 0)
continue;
/* A child is freed and removed from the list at the same time */
if (WARN_ON_ONCE(ei_child->is_freed))
- goto out;
- result = lookup_dir_entry(dentry, ei, ei_child);
- goto out;
+ return NULL;
+ return lookup_dir_entry(dentry, ei, ei_child);
}
for (int i = 0; i < ei->nr_entries; i++) {
@@ -563,14 +555,12 @@ static struct dentry *eventfs_root_lookup(struct inode *dir,
data = ei->data;
if (entry->callback(name, &mode, &data, &fops) <= 0)
- goto out;
+ return NULL;
+
+ return lookup_file_dentry(dentry, ei, i, mode, data, fops);
- result = lookup_file_dentry(dentry, ei, i, mode, data, fops);
- goto out;
}
- out:
- mutex_unlock(&eventfs_mutex);
- return result;
+ return NULL;
}
/*
@@ -586,8 +576,6 @@ static int eventfs_iterate(struct file *file, struct dir_context *ctx)
struct eventfs_inode *ei;
const char *name;
umode_t mode;
- int idx;
- int ret = -EINVAL;
int ino;
int i, r, c;
@@ -600,22 +588,18 @@ static int eventfs_iterate(struct file *file, struct dir_context *ctx)
c = ctx->pos - 2;
- idx = srcu_read_lock(&eventfs_srcu);
-
- mutex_lock(&eventfs_mutex);
- ei = READ_ONCE(ti->private);
- if (ei && ei->is_freed)
- ei = NULL;
- mutex_unlock(&eventfs_mutex);
+ guard(srcu)(&eventfs_srcu);
- if (!ei)
- goto out;
+ scoped_guard(mutex, &eventfs_mutex) {
+ ei = READ_ONCE(ti->private);
+ if (!ei || ei->is_freed)
+ return -EINVAL;
+ }
/*
* Need to create the dentries and inodes to have a consistent
* inode number.
*/
- ret = 0;
/* Start at 'c' to jump over already read entries */
for (i = c; i < ei->nr_entries; i++, ctx->pos++) {
@@ -624,21 +608,19 @@ static int eventfs_iterate(struct file *file, struct dir_context *ctx)
entry = &ei->entries[i];
name = entry->name;
- mutex_lock(&eventfs_mutex);
/* If ei->is_freed then just bail here, nothing more to do */
- if (ei->is_freed) {
- mutex_unlock(&eventfs_mutex);
- goto out;
+ scoped_guard(mutex, &eventfs_mutex) {
+ if (ei->is_freed)
+ return -EINVAL;
+ r = entry->callback(name, &mode, &cdata, &fops);
}
- r = entry->callback(name, &mode, &cdata, &fops);
- mutex_unlock(&eventfs_mutex);
if (r <= 0)
continue;
ino = EVENTFS_FILE_INODE_INO;
if (!dir_emit(ctx, name, strlen(name), ino, DT_REG))
- goto out;
+ return -EINVAL;
}
/* Subtract the skipped entries above */
@@ -661,19 +643,13 @@ static int eventfs_iterate(struct file *file, struct dir_context *ctx)
ino = eventfs_dir_ino(ei_child);
- if (!dir_emit(ctx, name, strlen(name), ino, DT_DIR))
- goto out_dec;
+ if (!dir_emit(ctx, name, strlen(name), ino, DT_DIR)) {
+ /* Incremented ctx->pos without adding something, reset it */
+ ctx->pos--;
+ return -EINVAL;
+ }
}
- ret = 1;
- out:
- srcu_read_unlock(&eventfs_srcu, idx);
-
- return ret;
-
- out_dec:
- /* Incremented ctx->pos without adding something, reset it */
- ctx->pos--;
- goto out;
+ return 1;
}
/**
@@ -730,11 +706,10 @@ struct eventfs_inode *eventfs_create_dir(const char *name, struct eventfs_inode
INIT_LIST_HEAD(&ei->children);
INIT_LIST_HEAD(&ei->list);
- mutex_lock(&eventfs_mutex);
- if (!parent->is_freed)
- list_add_tail(&ei->list, &parent->children);
- mutex_unlock(&eventfs_mutex);
-
+ scoped_guard(mutex, &eventfs_mutex) {
+ if (!parent->is_freed)
+ list_add_tail_rcu(&ei->list, &parent->children);
+ }
/* Was the parent freed? */
if (list_empty(&ei->list)) {
cleanup_ei(ei);
@@ -880,9 +855,8 @@ void eventfs_remove_dir(struct eventfs_inode *ei)
if (!ei)
return;
- mutex_lock(&eventfs_mutex);
+ guard(mutex)(&eventfs_mutex);
eventfs_remove_rec(ei, 0);
- mutex_unlock(&eventfs_mutex);
}
/**
diff --git a/fs/xfs/xfs_zone_alloc.c b/fs/xfs/xfs_zone_alloc.c
index e3d19b6dc64a..6b42572f9984 100644
--- a/fs/xfs/xfs_zone_alloc.c
+++ b/fs/xfs/xfs_zone_alloc.c
@@ -1214,7 +1214,7 @@ xfs_alloc_zone_info(
return zi;
out_free_bitmaps:
- while (--i > 0)
+ while (--i >= 0)
kvfree(zi->zi_used_bucket_bitmap[i]);
kfree(zi);
return NULL;
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
index 4e15583e0d25..f72e00517eb3 100644
--- a/include/acpi/actbl1.h
+++ b/include/acpi/actbl1.h
@@ -1386,6 +1386,12 @@ enum acpi_einj_command_status {
#define ACPI_EINJ_CXL_MEM_FATAL (1<<17)
#define ACPI_EINJ_VENDOR_DEFINED (1<<31)
+/* EINJV2 error types from EINJV2_GET_ERROR_TYPE (ACPI 6.6) */
+
+#define ACPI_EINJV2_PROCESSOR (1)
+#define ACPI_EINJV2_MEMORY (1<<1)
+#define ACPI_EINJV2_PCIE (1<<2)
+
/*******************************************************************************
*
* ERST - Error Record Serialization Table (ACPI 4.0)
diff --git a/include/drm/ttm/ttm_resource.h b/include/drm/ttm/ttm_resource.h
index 33e80f30b8b8..a5d386583fb6 100644
--- a/include/drm/ttm/ttm_resource.h
+++ b/include/drm/ttm/ttm_resource.h
@@ -448,6 +448,8 @@ void ttm_resource_add_bulk_move(struct ttm_resource *res,
struct ttm_buffer_object *bo);
void ttm_resource_del_bulk_move(struct ttm_resource *res,
struct ttm_buffer_object *bo);
+void ttm_resource_del_bulk_move_unevictable(struct ttm_resource *res,
+ struct ttm_buffer_object *bo);
void ttm_resource_move_to_lru_tail(struct ttm_resource *res);
void ttm_resource_init(struct ttm_buffer_object *bo,
diff --git a/include/dt-bindings/clock/qcom,gcc-sc8180x.h b/include/dt-bindings/clock/qcom,gcc-sc8180x.h
index b9d8438a15ff..9ed7b794aacc 100644
--- a/include/dt-bindings/clock/qcom,gcc-sc8180x.h
+++ b/include/dt-bindings/clock/qcom,gcc-sc8180x.h
@@ -322,5 +322,10 @@
#define USB30_MP_GDSC 8
#define USB30_PRIM_GDSC 9
#define USB30_SEC_GDSC 10
+#define HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC 11
+#define HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC 12
+#define HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC 13
+#define HLOS1_VOTE_TURING_MMU_TBU0_GDSC 14
+#define HLOS1_VOTE_TURING_MMU_TBU1_GDSC 15
#endif
diff --git a/include/dt-bindings/clock/qcom,glymur-gcc.h b/include/dt-bindings/clock/qcom,glymur-gcc.h
index 10c12b8c51c3..6907653c7992 100644
--- a/include/dt-bindings/clock/qcom,glymur-gcc.h
+++ b/include/dt-bindings/clock/qcom,glymur-gcc.h
@@ -574,5 +574,6 @@
#define GCC_VIDEO_AXI0_CLK_ARES 89
#define GCC_VIDEO_AXI1_CLK_ARES 90
#define GCC_VIDEO_BCR 91
+#define GCC_VIDEO_AXI0C_CLK_ARES 92
#endif
diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h
index b907e6c2307d..260d7968cf72 100644
--- a/include/linux/cdrom.h
+++ b/include/linux/cdrom.h
@@ -108,6 +108,7 @@ int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev,
extern unsigned int cdrom_check_events(struct cdrom_device_info *cdi,
unsigned int clearing);
+extern void cdrom_probe_write_features(struct cdrom_device_info *cdi);
extern int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi);
extern void unregister_cdrom(struct cdrom_device_info *cdi);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index cc894fc38971..4317c5a312bd 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -372,7 +372,7 @@ struct cpufreq_driver {
* conditions) scale invariance can be disabled, which causes the
* schedutil governor to fall back to the latter.
*/
- void (*adjust_perf)(unsigned int cpu,
+ void (*adjust_perf)(struct cpufreq_policy *policy,
unsigned long min_perf,
unsigned long target_perf,
unsigned long capacity);
@@ -617,7 +617,7 @@ struct cpufreq_governor {
/* Pass a target to the cpufreq driver */
unsigned int cpufreq_driver_fast_switch(struct cpufreq_policy *policy,
unsigned int target_freq);
-void cpufreq_driver_adjust_perf(unsigned int cpu,
+void cpufreq_driver_adjust_perf(struct cpufreq_policy *policy,
unsigned long min_perf,
unsigned long target_perf,
unsigned long capacity);
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 62cd7b35a29c..22ba327ec227 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -92,7 +92,6 @@ enum cpuhp_state {
CPUHP_NET_DEV_DEAD,
CPUHP_IOMMU_IOVA_DEAD,
CPUHP_AP_ARM_CACHE_B15_RAC_DEAD,
- CPUHP_PADATA_DEAD,
CPUHP_AP_DTPM_CPU_DEAD,
CPUHP_RANDOM_PREPARE,
CPUHP_WORKQUEUE_PREP,
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index 927f8a8b7a1d..2eedf44e6801 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -60,6 +60,7 @@ enum dmi_entry_type {
DMI_ENTRY_OOB_REMOTE_ACCESS,
DMI_ENTRY_BIS_ENTRY,
DMI_ENTRY_SYSTEM_BOOT,
+ DMI_ENTRY_64_MEM_ERROR,
DMI_ENTRY_MGMT_DEV,
DMI_ENTRY_MGMT_DEV_COMPONENT,
DMI_ENTRY_MGMT_DEV_THRES,
@@ -69,6 +70,10 @@ enum dmi_entry_type {
DMI_ENTRY_ADDITIONAL,
DMI_ENTRY_ONBOARD_DEV_EXT,
DMI_ENTRY_MGMT_CONTROLLER_HOST,
+ DMI_ENTRY_TPM_DEVICE,
+ DMI_ENTRY_PROCESSOR_ADDITIONAL,
+ DMI_ENTRY_FIRMWARE_INVENTORY,
+ DMI_ENTRY_STRING_PROPERTY,
DMI_ENTRY_INACTIVE = 126,
DMI_ENTRY_END_OF_TABLE = 127,
};
diff --git a/include/linux/dpll.h b/include/linux/dpll.h
index 2ce295b46b8c..8f97120ee7b3 100644
--- a/include/linux/dpll.h
+++ b/include/linux/dpll.h
@@ -276,6 +276,7 @@ int dpll_pin_ref_sync_pair_add(struct dpll_pin *pin,
int dpll_device_change_ntf(struct dpll_device *dpll);
+int __dpll_pin_change_ntf(struct dpll_pin *pin);
int dpll_pin_change_ntf(struct dpll_pin *pin);
int register_dpll_notifier(struct notifier_block *nb);
diff --git a/include/linux/fsl/mc.h b/include/linux/fsl/mc.h
index 897d6211c163..1da63f2d7040 100644
--- a/include/linux/fsl/mc.h
+++ b/include/linux/fsl/mc.h
@@ -178,9 +178,6 @@ struct fsl_mc_obj_desc {
* @regions: pointer to array of MMIO region entries
* @irqs: pointer to array of pointers to interrupts allocated to this device
* @resource: generic resource associated with this MC object device, if any.
- * @driver_override: driver name to force a match; do not set directly,
- * because core frees it; use driver_set_override() to
- * set or clear it.
*
* Generic device object for MC object devices that are "attached" to a
* MC bus.
@@ -214,7 +211,6 @@ struct fsl_mc_device {
struct fsl_mc_device_irq **irqs;
struct fsl_mc_resource *resource;
struct device_link *consumer_link;
- const char *driver_override;
};
#define to_fsl_mc_device(_dev) \
diff --git a/include/linux/fsl/ntmp.h b/include/linux/fsl/ntmp.h
index 916dc4fe7de3..83a449b4d6ec 100644
--- a/include/linux/fsl/ntmp.h
+++ b/include/linux/fsl/ntmp.h
@@ -31,6 +31,12 @@ struct netc_tbl_vers {
u8 rsst_ver;
};
+struct netc_swcbd {
+ void *buf;
+ dma_addr_t dma;
+ size_t size;
+};
+
struct netc_cbdr {
struct device *dev;
struct netc_cbdr_regs regs;
@@ -44,9 +50,10 @@ struct netc_cbdr {
void *addr_base_align;
dma_addr_t dma_base;
dma_addr_t dma_base_align;
+ struct netc_swcbd *swcbd;
/* Serialize the order of command BD ring */
- spinlock_t ring_lock;
+ struct mutex ring_lock;
};
struct ntmp_user {
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 31324609af4d..101e05acf931 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -998,6 +998,8 @@ struct hid_field *hid_find_field(struct hid_device *hdev, unsigned int report_ty
int hid_set_field(struct hid_field *, unsigned, __s32);
int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size,
int interrupt);
+int hid_safe_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data,
+ size_t bufsize, u32 size, int interrupt);
struct hid_field *hidinput_get_led_field(struct hid_device *hid);
unsigned int hidinput_count_leds(struct hid_device *hid);
__s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code);
@@ -1266,8 +1268,8 @@ static inline u32 hid_report_len(struct hid_report *report)
return DIV_ROUND_UP(report->size, 8) + (report->id > 0);
}
-int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size,
- int interrupt);
+int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *data,
+ size_t bufsize, u32 size, int interrupt);
/* HID quirks API */
unsigned long hid_lookup_quirk(const struct hid_device *hdev);
diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h
index a2e47dbcf82c..19fffa4574a4 100644
--- a/include/linux/hid_bpf.h
+++ b/include/linux/hid_bpf.h
@@ -72,8 +72,8 @@ struct hid_ops {
int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len,
u64 source, bool from_bpf);
int (*hid_input_report)(struct hid_device *hid, enum hid_report_type type,
- u8 *data, u32 size, int interrupt, u64 source, bool from_bpf,
- bool lock_already_taken);
+ u8 *data, size_t bufsize, u32 size, int interrupt, u64 source,
+ bool from_bpf, bool lock_already_taken);
struct module *owner;
const struct bus_type *bus_type;
};
@@ -200,7 +200,8 @@ struct hid_bpf {
#ifdef CONFIG_HID_BPF
u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data,
- u32 *size, int interrupt, u64 source, bool from_bpf);
+ size_t *buf_size, u32 *size, int interrupt, u64 source,
+ bool from_bpf);
int dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
unsigned char reportnum, __u8 *buf,
u32 size, enum hid_report_type rtype,
@@ -215,8 +216,11 @@ int hid_bpf_device_init(struct hid_device *hid);
const u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc, unsigned int *size);
#else /* CONFIG_HID_BPF */
static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type,
- u8 *data, u32 *size, int interrupt,
- u64 source, bool from_bpf) { return data; }
+ u8 *data, size_t *buf_size, u32 *size,
+ int interrupt, u64 source, bool from_bpf)
+{
+ return data;
+}
static inline int dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
unsigned char reportnum, u8 *buf,
u32 size, enum hid_report_type rtype,
diff --git a/include/linux/ieee80211-eht.h b/include/linux/ieee80211-eht.h
index f8e9f5d36d2a..a97b1d01f3ac 100644
--- a/include/linux/ieee80211-eht.h
+++ b/include/linux/ieee80211-eht.h
@@ -251,8 +251,8 @@ struct ieee80211_eht_operation_info {
#define IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF 0x40
#define IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK 0x07
-#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_80MHZ 0x08
-#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_160MHZ 0x30
+#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_80MHZ 0x10
+#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_160MHZ 0x20
#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_320MHZ 0x40
#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK 0x78
#define IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP 0x80
diff --git a/include/linux/iopoll.h b/include/linux/iopoll.h
index bdd2e0652bc3..53edd69acb9b 100644
--- a/include/linux/iopoll.h
+++ b/include/linux/iopoll.h
@@ -159,7 +159,7 @@
*
* This macro does not rely on timekeeping. Hence it is safe to call even when
* timekeeping is suspended, at the expense of an underestimation of wall clock
- * time, which is rather minimal with a non-zero delay_us.
+ * time, which is rather minimal with a non-zero @delay_us.
*
* When available, you'll probably want to use one of the specialized
* macros defined below rather than this macro directly.
@@ -167,9 +167,9 @@
* Returns: 0 on success and -ETIMEDOUT upon a timeout. In either
* case, the last read value at @args is stored in @val.
*/
-#define read_poll_timeout_atomic(op, val, cond, sleep_us, timeout_us, \
- sleep_before_read, args...) \
- poll_timeout_us_atomic((val) = op(args), cond, sleep_us, timeout_us, sleep_before_read)
+#define read_poll_timeout_atomic(op, val, cond, delay_us, timeout_us, \
+ delay_before_read, args...) \
+ poll_timeout_us_atomic((val) = op(args), cond, delay_us, timeout_us, delay_before_read)
/**
* readx_poll_timeout - Periodically poll an address until a condition is met or a timeout occurs
diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm-gic-v5.h
index b78488df6c98..102924fd0193 100644
--- a/include/linux/irqchip/arm-gic-v5.h
+++ b/include/linux/irqchip/arm-gic-v5.h
@@ -398,9 +398,6 @@ struct gicv5_its_itt_cfg {
void gicv5_init_lpis(u32 max);
void gicv5_deinit_lpis(void);
-int gicv5_alloc_lpi(void);
-void gicv5_free_lpi(u32 lpi);
-
void __init gicv5_its_of_probe(struct device_node *parent);
void __init gicv5_its_acpi_probe(void);
#endif
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index 7d22d4c4ea2e..8667f72503d9 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -426,14 +426,9 @@ extern char *parse_args(const char *name,
void *arg, parse_unknown_fn unknown);
/* Called by module remove. */
-#ifdef CONFIG_SYSFS
-extern void destroy_params(const struct kernel_param *params, unsigned num);
-#else
-static inline void destroy_params(const struct kernel_param *params,
- unsigned num)
-{
-}
-#endif /* !CONFIG_SYSFS */
+#ifdef CONFIG_MODULES
+void module_destroy_params(const struct kernel_param *params, unsigned int num);
+#endif
/* All the helper functions */
/* The macros to do compile-time type checking stolen from Jakub
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 6a024cf1c53a..f2f80103649d 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -290,6 +290,12 @@
SPI_MEM_OP_NO_DUMMY, \
SPI_MEM_OP_NO_DATA)
+#define SPINAND_PAGE_READ_PACKED_8D_8D_0_OP(addr) \
+ SPI_MEM_OP(SPI_MEM_DTR_OP_PACKED_CMD(0x13, addr >> 16, 8), \
+ SPI_MEM_DTR_OP_ADDR(2, addr & 0xffff, 8), \
+ SPI_MEM_OP_NO_DUMMY, \
+ SPI_MEM_OP_NO_DATA)
+
#define SPINAND_PAGE_READ_FROM_CACHE_8D_8D_8D_OP(addr, ndummy, buf, len, freq) \
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9d, 8), \
SPI_MEM_DTR_OP_ADDR(2, addr, 8), \
@@ -482,6 +488,7 @@ struct spinand_ecc_info {
#define SPINAND_HAS_PROG_PLANE_SELECT_BIT BIT(2)
#define SPINAND_HAS_READ_PLANE_SELECT_BIT BIT(3)
#define SPINAND_NO_RAW_ACCESS BIT(4)
+#define SPINAND_ODTR_PACKED_PAGE_READ BIT(5)
/**
* struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure
diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index ecaa0440f6ec..f57d2a97da57 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -87,12 +87,12 @@ do { \
struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
#ifdef CONFIG_DEBUG_LOCK_ALLOC
-void mutex_init_lockep(struct mutex *lock, const char *name, struct lock_class_key *key);
+void mutex_init_lockdep(struct mutex *lock, const char *name, struct lock_class_key *key);
static inline void __mutex_init(struct mutex *lock, const char *name,
struct lock_class_key *key)
{
- mutex_init_lockep(lock, name, key);
+ mutex_init_lockdep(lock, name, key);
}
#else
extern void mutex_init_generic(struct mutex *lock);
@@ -146,7 +146,7 @@ static inline void __mutex_init(struct mutex *lock, const char *name,
{
mutex_rt_init_generic(lock);
}
-#endif /* !CONFIG_LOCKDEP */
+#endif /* !CONFIG_DEBUG_LOCK_ALLOC */
#endif /* CONFIG_PREEMPT_RT */
#ifdef CONFIG_DEBUG_MUTEXES
diff --git a/include/linux/nstree.h b/include/linux/nstree.h
index 175e4625bfa6..5b64d4572881 100644
--- a/include/linux/nstree.h
+++ b/include/linux/nstree.h
@@ -61,7 +61,7 @@ static inline void __ns_tree_add(struct ns_common *ns, struct ns_tree_root *ns_t
/**
* ns_tree_add_raw - Add a namespace to a namespace
- * @ns: Namespace to add
+ * @__ns: Namespace to add
*
* This function adds a namespace to the appropriate namespace tree
* without assigning a id.
@@ -70,7 +70,7 @@ static inline void __ns_tree_add(struct ns_common *ns, struct ns_tree_root *ns_t
/**
* ns_tree_add - Add a namespace to a namespace tree
- * @ns: Namespace to add
+ * @__ns: Namespace to add
*
* This function assigns a new id to the namespace and adds it to the
* appropriate namespace tree and list.
@@ -81,7 +81,7 @@ static inline void __ns_tree_add(struct ns_common *ns, struct ns_tree_root *ns_t
/**
* ns_tree_remove - Remove a namespace from a namespace tree
- * @ns: Namespace to remove
+ * @__ns: Namespace to remove
*
* This function removes a namespace from the appropriate namespace
* tree and list.
diff --git a/include/linux/padata.h b/include/linux/padata.h
index 765f2778e264..b6232bea6edf 100644
--- a/include/linux/padata.h
+++ b/include/linux/padata.h
@@ -149,23 +149,23 @@ struct padata_mt_job {
/**
* struct padata_instance - The overall control structure.
*
- * @cpu_online_node: Linkage for CPU online callback.
- * @cpu_dead_node: Linkage for CPU offline callback.
+ * @cpuhp_node: Linkage for CPU hotplug callbacks.
* @parallel_wq: The workqueue used for parallel work.
* @serial_wq: The workqueue used for serial work.
* @pslist: List of padata_shell objects attached to this instance.
* @cpumask: User supplied cpumasks for parallel and serial works.
+ * @validate_cpumask: Internal cpumask used to validate @cpumask during hotplug.
* @kobj: padata instance kernel object.
* @lock: padata instance lock.
* @flags: padata flags.
*/
struct padata_instance {
- struct hlist_node cpu_online_node;
- struct hlist_node cpu_dead_node;
+ struct hlist_node cpuhp_node;
struct workqueue_struct *parallel_wq;
struct workqueue_struct *serial_wq;
struct list_head pslist;
struct padata_cpumask cpumask;
+ cpumask_var_t validate_cpumask;
struct kobject kobj;
struct mutex lock;
u8 flags;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 1c270f1d5123..57e9463e4347 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -575,12 +575,6 @@ struct pci_dev {
u8 supported_speeds; /* Supported Link Speeds Vector */
phys_addr_t rom; /* Physical address if not from BAR */
size_t romlen; /* Length if not from BAR */
- /*
- * Driver name to force a match. Do not set directly, because core
- * frees it. Use driver_set_override() to set or clear it.
- */
- const char *driver_override;
-
unsigned long priv_flags; /* Private flags for the PCI driver */
/* These methods index pci_reset_fn_methods[] */
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 93ba0143ca47..38d1814ab8a5 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -49,8 +49,8 @@
struct dev_pm_domain_attach_data {
const char * const *pd_names;
- const u32 num_pd_names;
- const u32 pd_flags;
+ u32 num_pd_names;
+ u32 pd_flags;
};
struct dev_pm_domain_list {
diff --git a/include/linux/ppp_defs.h b/include/linux/ppp_defs.h
index b7e57fdbd413..b1d1f46d7d3b 100644
--- a/include/linux/ppp_defs.h
+++ b/include/linux/ppp_defs.h
@@ -8,6 +8,7 @@
#define _PPP_DEFS_H_
#include <linux/crc-ccitt.h>
+#include <linux/skbuff.h>
#include <uapi/linux/ppp_defs.h>
#define PPP_FCS(fcs, c) crc_ccitt_byte(fcs, c)
@@ -25,4 +26,19 @@ static inline bool ppp_proto_is_valid(u16 proto)
return !!((proto & 0x0101) == 0x0001);
}
+/**
+ * ppp_skb_is_compressed_proto - checks if PPP protocol in a skb is compressed
+ * @skb: skb to check
+ *
+ * Check if the PPP protocol field is compressed (the least significant
+ * bit of the most significant octet is 1). skb->data must point to the PPP
+ * protocol header.
+ *
+ * Return: Whether the PPP protocol field is compressed.
+ */
+static inline bool ppp_skb_is_compressed_proto(const struct sk_buff *skb)
+{
+ return unlikely(skb->data[0] & 0x01);
+}
+
#endif /* _PPP_DEFS_H_ */
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 54e3c621fec3..f594c1266bfd 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -815,7 +815,8 @@ static inline void print_hex_dump_devel(const char *prefix_str, int prefix_type,
#endif
/**
- * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params
+ * print_hex_dump_bytes - shorthand form of print_hex_dump_debug() with default
+ * params
* @prefix_str: string to prefix each line with;
* caller supplies trailing spaces for alignment if desired
* @prefix_type: controls whether prefix of an offset, address, or none
@@ -823,7 +824,7 @@ static inline void print_hex_dump_devel(const char *prefix_str, int prefix_type,
* @buf: data blob to dump
* @len: number of bytes in the @buf
*
- * Calls print_hex_dump(), with log level of KERN_DEBUG,
+ * Calls print_hex_dump_debug(), with log level of KERN_DEBUG,
* rowsize of 16, groupsize of 1, and ASCII output included.
*/
#define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index c334f82ed385..f9c0f9d7c9d9 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -44,14 +44,7 @@ int dquot_initialize(struct inode *inode);
bool dquot_initialize_needed(struct inode *inode);
void dquot_drop(struct inode *inode);
struct dquot *dqget(struct super_block *sb, struct kqid qid);
-static inline struct dquot *dqgrab(struct dquot *dquot)
-{
- /* Make sure someone else has active reference to dquot */
- WARN_ON_ONCE(!atomic_read(&dquot->dq_count));
- WARN_ON_ONCE(!test_bit(DQ_ACTIVE_B, &dquot->dq_flags));
- atomic_inc(&dquot->dq_count);
- return dquot;
-}
+struct dquot *dqgrab(struct dquot *dquot);
static inline bool dquot_is_busy(struct dquot *dquot)
{
diff --git a/include/linux/rculist.h b/include/linux/rculist.h
index 2abba7552605..e3bc44225692 100644
--- a/include/linux/rculist.h
+++ b/include/linux/rculist.h
@@ -261,6 +261,35 @@ static inline void list_replace_rcu(struct list_head *old,
old->prev = LIST_POISON2;
}
+static inline void __list_splice_rcu(struct list_head *list,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+
+ last->next = next;
+ first->prev = prev;
+ next->prev = last;
+ rcu_assign_pointer(list_next_rcu(prev), first);
+}
+
+/**
+ * list_splice_rcu - splice a non-RCU list into an RCU-protected list,
+ * designed for stacks.
+ * @list: the non RCU-protected list to splice
+ * @head: the place in the existing RCU-protected list to splice
+ *
+ * The list pointed to by @head can be RCU-read traversed concurrently with
+ * this function.
+ */
+static inline void list_splice_rcu(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice_rcu(list, head, head->next);
+}
+
/**
* __list_splice_init_rcu - join an RCU-protected list into an existing list.
* @list: the RCU-protected list to splice
diff --git a/include/linux/rseq.h b/include/linux/rseq.h
index f446909551df..7ef79b25e714 100644
--- a/include/linux/rseq.h
+++ b/include/linux/rseq.h
@@ -9,6 +9,11 @@
void __rseq_handle_slowpath(struct pt_regs *regs);
+static __always_inline bool rseq_v2(struct task_struct *t)
+{
+ return IS_ENABLED(CONFIG_GENERIC_IRQ_ENTRY) && likely(t->rseq.event.has_rseq > 1);
+}
+
/* Invoked from resume_user_mode_work() */
static inline void rseq_handle_slowpath(struct pt_regs *regs)
{
@@ -16,8 +21,7 @@ static inline void rseq_handle_slowpath(struct pt_regs *regs)
if (current->rseq.event.slowpath)
__rseq_handle_slowpath(regs);
} else {
- /* '&' is intentional to spare one conditional branch */
- if (current->rseq.event.sched_switch & current->rseq.event.has_rseq)
+ if (current->rseq.event.sched_switch && current->rseq.event.has_rseq)
__rseq_handle_slowpath(regs);
}
}
@@ -30,9 +34,9 @@ void __rseq_signal_deliver(int sig, struct pt_regs *regs);
*/
static inline void rseq_signal_deliver(struct ksignal *ksig, struct pt_regs *regs)
{
- if (IS_ENABLED(CONFIG_GENERIC_IRQ_ENTRY)) {
- /* '&' is intentional to spare one conditional branch */
- if (current->rseq.event.has_rseq & current->rseq.event.user_irq)
+ if (rseq_v2(current)) {
+ /* has_rseq is implied in rseq_v2() */
+ if (current->rseq.event.user_irq)
__rseq_signal_deliver(ksig->sig, regs);
} else {
if (current->rseq.event.has_rseq)
@@ -50,15 +54,22 @@ static __always_inline void rseq_sched_switch_event(struct task_struct *t)
{
struct rseq_event *ev = &t->rseq.event;
- if (IS_ENABLED(CONFIG_GENERIC_IRQ_ENTRY)) {
+ /*
+ * Only apply the user_irq optimization for RSEQ ABI V2 registrations.
+ * Legacy users like TCMalloc rely on the original ABI V1 behaviour
+ * which updates IDs on every context swtich.
+ */
+ if (rseq_v2(t)) {
/*
- * Avoid a boat load of conditionals by using simple logic
- * to determine whether NOTIFY_RESUME needs to be raised.
+ * Avoid a boat load of conditionals by using simple logic to
+ * determine whether TIF_NOTIFY_RESUME or TIF_RSEQ needs to be
+ * raised.
*
- * It's required when the CPU or MM CID has changed or
- * the entry was from user space.
+ * It's required when the CPU or MM CID has changed or the entry
+ * was via interrupt from user space. ev->has_rseq does not have
+ * to be evaluated here because rseq_v2() implies has_rseq.
*/
- bool raise = (ev->user_irq | ev->ids_changed) & ev->has_rseq;
+ bool raise = ev->user_irq | ev->ids_changed;
if (raise) {
ev->sched_switch = true;
@@ -66,6 +77,7 @@ static __always_inline void rseq_sched_switch_event(struct task_struct *t)
}
} else {
if (ev->has_rseq) {
+ t->rseq.event.ids_changed = true;
t->rseq.event.sched_switch = true;
rseq_raise_notify_resume(t);
}
@@ -161,6 +173,7 @@ static inline unsigned int rseq_alloc_align(void)
}
#else /* CONFIG_RSEQ */
+static inline bool rseq_v2(struct task_struct *t) { return false; }
static inline void rseq_handle_slowpath(struct pt_regs *regs) { }
static inline void rseq_signal_deliver(struct ksignal *ksig, struct pt_regs *regs) { }
static inline void rseq_sched_switch_event(struct task_struct *t) { }
diff --git a/include/linux/rseq_entry.h b/include/linux/rseq_entry.h
index c6831c93cd6e..413a3543fbe8 100644
--- a/include/linux/rseq_entry.h
+++ b/include/linux/rseq_entry.h
@@ -110,6 +110,20 @@ static __always_inline void rseq_slice_clear_grant(struct task_struct *t)
t->rseq.slice.state.granted = false;
}
+/*
+ * Open coded, so it can be invoked within a user access region.
+ *
+ * This clears the user space state of the time slice extensions field only when
+ * the task has registered the optimized RSEQ_ABI V2. Some legacy registrations,
+ * e.g. TCMalloc, have conflicting non-ABI fields in struct RSEQ, which would be
+ * overwritten by an unconditional write.
+ */
+#define rseq_slice_clear_user(rseq, efault) \
+do { \
+ if (rseq_slice_extension_enabled()) \
+ unsafe_put_user(0U, &rseq->slice_ctrl.all, efault); \
+} while (0)
+
static __always_inline bool rseq_grant_slice_extension(bool work_pending)
{
struct task_struct *curr = current;
@@ -220,10 +234,10 @@ static __always_inline bool rseq_slice_extension_enabled(void) { return false; }
static __always_inline bool rseq_arm_slice_extension_timer(void) { return false; }
static __always_inline void rseq_slice_clear_grant(struct task_struct *t) { }
static __always_inline bool rseq_grant_slice_extension(bool work_pending) { return false; }
+#define rseq_slice_clear_user(rseq, efault) do { } while (0)
#endif /* !CONFIG_RSEQ_SLICE_EXTENSION */
bool rseq_debug_update_user_cs(struct task_struct *t, struct pt_regs *regs, unsigned long csaddr);
-bool rseq_debug_validate_ids(struct task_struct *t);
static __always_inline void rseq_note_user_irq_entry(void)
{
@@ -343,43 +357,6 @@ bool rseq_debug_update_user_cs(struct task_struct *t, struct pt_regs *regs,
return false;
}
-/*
- * On debug kernels validate that user space did not mess with it if the
- * debug branch is enabled.
- */
-bool rseq_debug_validate_ids(struct task_struct *t)
-{
- struct rseq __user *rseq = t->rseq.usrptr;
- u32 cpu_id, uval, node_id;
-
- /*
- * On the first exit after registering the rseq region CPU ID is
- * RSEQ_CPU_ID_UNINITIALIZED and node_id in user space is 0!
- */
- node_id = t->rseq.ids.cpu_id != RSEQ_CPU_ID_UNINITIALIZED ?
- cpu_to_node(t->rseq.ids.cpu_id) : 0;
-
- scoped_user_read_access(rseq, efault) {
- unsafe_get_user(cpu_id, &rseq->cpu_id_start, efault);
- if (cpu_id != t->rseq.ids.cpu_id)
- goto die;
- unsafe_get_user(uval, &rseq->cpu_id, efault);
- if (uval != cpu_id)
- goto die;
- unsafe_get_user(uval, &rseq->node_id, efault);
- if (uval != node_id)
- goto die;
- unsafe_get_user(uval, &rseq->mm_cid, efault);
- if (uval != t->rseq.ids.mm_cid)
- goto die;
- }
- return true;
-die:
- t->rseq.event.fatal = true;
-efault:
- return false;
-}
-
#endif /* RSEQ_BUILD_SLOW_PATH */
/*
@@ -489,37 +466,50 @@ rseq_update_user_cs(struct task_struct *t, struct pt_regs *regs, unsigned long c
* faults in task context are fatal too.
*/
static rseq_inline
-bool rseq_set_ids_get_csaddr(struct task_struct *t, struct rseq_ids *ids,
- u32 node_id, u64 *csaddr)
+bool rseq_set_ids_get_csaddr(struct task_struct *t, struct rseq_ids *ids, u64 *csaddr)
{
struct rseq __user *rseq = t->rseq.usrptr;
- if (static_branch_unlikely(&rseq_debug_enabled)) {
- if (!rseq_debug_validate_ids(t))
- return false;
- }
-
scoped_user_rw_access(rseq, efault) {
+ /* Validate the R/O fields for debug and optimized mode */
+ if (static_branch_unlikely(&rseq_debug_enabled) || rseq_v2(t)) {
+ u32 cpu_id, uval;
+
+ unsafe_get_user(cpu_id, &rseq->cpu_id_start, efault);
+ if (cpu_id != t->rseq.ids.cpu_id)
+ goto die;
+ unsafe_get_user(uval, &rseq->cpu_id, efault);
+ if (uval != cpu_id)
+ goto die;
+ unsafe_get_user(uval, &rseq->node_id, efault);
+ if (uval != t->rseq.ids.node_id)
+ goto die;
+ unsafe_get_user(uval, &rseq->mm_cid, efault);
+ if (uval != t->rseq.ids.mm_cid)
+ goto die;
+ }
+
unsafe_put_user(ids->cpu_id, &rseq->cpu_id_start, efault);
unsafe_put_user(ids->cpu_id, &rseq->cpu_id, efault);
- unsafe_put_user(node_id, &rseq->node_id, efault);
+ unsafe_put_user(ids->node_id, &rseq->node_id, efault);
unsafe_put_user(ids->mm_cid, &rseq->mm_cid, efault);
if (csaddr)
unsafe_get_user(*csaddr, &rseq->rseq_cs, efault);
- /* Open coded, so it's in the same user access region */
- if (rseq_slice_extension_enabled()) {
- /* Unconditionally clear it, no point in conditionals */
- unsafe_put_user(0U, &rseq->slice_ctrl.all, efault);
- }
+ /* RSEQ ABI V2 only operations */
+ if (rseq_v2(t))
+ rseq_slice_clear_user(rseq, efault);
}
rseq_slice_clear_grant(t);
/* Cache the new values */
- t->rseq.ids.cpu_cid = ids->cpu_cid;
+ t->rseq.ids = *ids;
rseq_stat_inc(rseq_stats.ids);
rseq_trace_update(t, ids);
return true;
+
+die:
+ t->rseq.event.fatal = true;
efault:
return false;
}
@@ -529,11 +519,11 @@ bool rseq_set_ids_get_csaddr(struct task_struct *t, struct rseq_ids *ids,
* is in a critical section.
*/
static rseq_inline bool rseq_update_usr(struct task_struct *t, struct pt_regs *regs,
- struct rseq_ids *ids, u32 node_id)
+ struct rseq_ids *ids)
{
u64 csaddr;
- if (!rseq_set_ids_get_csaddr(t, ids, node_id, &csaddr))
+ if (!rseq_set_ids_get_csaddr(t, ids, &csaddr))
return false;
/*
@@ -602,6 +592,14 @@ static __always_inline bool rseq_exit_user_update(struct pt_regs *regs, struct t
* interrupts disabled
*/
guard(pagefault)();
+ /*
+ * This optimization is only valid when the task registered for the
+ * optimized RSEQ_ABI_V2 variant. Some legacy users rely on the original
+ * RSEQ implementation behaviour which unconditionally updated the IDs.
+ * rseq_sched_switch_event() ensures that legacy registrations always
+ * have both sched_switch and ids_changed set, which is compatible with
+ * the historical TIF_NOTIFY_RESUME behaviour.
+ */
if (likely(!t->rseq.event.ids_changed)) {
struct rseq __user *rseq = t->rseq.usrptr;
/*
@@ -613,11 +611,9 @@ static __always_inline bool rseq_exit_user_update(struct pt_regs *regs, struct t
scoped_user_rw_access(rseq, efault) {
unsafe_get_user(csaddr, &rseq->rseq_cs, efault);
- /* Open coded, so it's in the same user access region */
- if (rseq_slice_extension_enabled()) {
- /* Unconditionally clear it, no point in conditionals */
- unsafe_put_user(0U, &rseq->slice_ctrl.all, efault);
- }
+ /* RSEQ ABI V2 only operations */
+ if (rseq_v2(t))
+ rseq_slice_clear_user(rseq, efault);
}
rseq_slice_clear_grant(t);
@@ -630,12 +626,12 @@ static __always_inline bool rseq_exit_user_update(struct pt_regs *regs, struct t
}
struct rseq_ids ids = {
- .cpu_id = task_cpu(t),
- .mm_cid = task_mm_cid(t),
+ .cpu_id = task_cpu(t),
+ .mm_cid = task_mm_cid(t),
+ .node_id = cpu_to_node(ids.cpu_id),
};
- u32 node_id = cpu_to_node(ids.cpu_id);
- return rseq_update_usr(t, regs, &ids, node_id);
+ return rseq_update_usr(t, regs, &ids);
efault:
return false;
}
diff --git a/include/linux/rseq_types.h b/include/linux/rseq_types.h
index 0b42045988db..85739a63e85e 100644
--- a/include/linux/rseq_types.h
+++ b/include/linux/rseq_types.h
@@ -9,6 +9,12 @@
#ifdef CONFIG_RSEQ
struct rseq;
+/*
+ * rseq_event::has_rseq contains the ABI version number so preserving it
+ * in AND operations requires a mask.
+ */
+#define RSEQ_HAS_RSEQ_VERSION_MASK 0xff
+
/**
* struct rseq_event - Storage for rseq related event management
* @all: Compound to initialize and clear the data efficiently
@@ -17,7 +23,8 @@ struct rseq;
* exit to user
* @ids_changed: Indicator that IDs need to be updated
* @user_irq: True on interrupt entry from user mode
- * @has_rseq: True if the task has a rseq pointer installed
+ * @has_rseq: Greater than 0 if the task has a rseq pointer installed.
+ * Contains the RSEQ version number
* @error: Compound error code for the slow path to analyze
* @fatal: User space data corrupted or invalid
* @slowpath: Indicator that slow path processing via TIF_NOTIFY_RESUME
@@ -59,8 +66,9 @@ struct rseq_event {
* compiler emit a single compare on 64-bit
* @cpu_id: The CPU ID which was written last to user space
* @mm_cid: The MM CID which was written last to user space
+ * @node_id: The node ID which was written last to user space
*
- * @cpu_id and @mm_cid are updated when the data is written to user space.
+ * @cpu_id, @mm_cid and @node_id are updated when the data is written to user space.
*/
struct rseq_ids {
union {
@@ -70,6 +78,7 @@ struct rseq_ids {
u32 mm_cid;
};
};
+ u32 node_id;
};
/**
diff --git a/include/linux/rwlock.h b/include/linux/rwlock.h
index 3390d21c95dd..21ceefc4a49f 100644
--- a/include/linux/rwlock.h
+++ b/include/linux/rwlock.h
@@ -30,10 +30,10 @@ do { \
#ifdef CONFIG_DEBUG_SPINLOCK
extern void do_raw_read_lock(rwlock_t *lock) __acquires_shared(lock);
- extern int do_raw_read_trylock(rwlock_t *lock);
+ extern int do_raw_read_trylock(rwlock_t *lock) __cond_acquires_shared(true, lock);
extern void do_raw_read_unlock(rwlock_t *lock) __releases_shared(lock);
extern void do_raw_write_lock(rwlock_t *lock) __acquires(lock);
- extern int do_raw_write_trylock(rwlock_t *lock);
+extern int do_raw_write_trylock(rwlock_t *lock) __cond_acquires(true, lock);
extern void do_raw_write_unlock(rwlock_t *lock) __releases(lock);
#else
# define do_raw_read_lock(rwlock) do {__acquire_shared(lock); arch_read_lock(&(rwlock)->raw_lock); } while (0)
diff --git a/include/linux/rwlock_api_smp.h b/include/linux/rwlock_api_smp.h
index 61a852609eab..9e02a5f28cd1 100644
--- a/include/linux/rwlock_api_smp.h
+++ b/include/linux/rwlock_api_smp.h
@@ -23,7 +23,7 @@ void __lockfunc _raw_write_lock_bh(rwlock_t *lock) __acquires(lock);
void __lockfunc _raw_read_lock_irq(rwlock_t *lock) __acquires_shared(lock);
void __lockfunc _raw_write_lock_irq(rwlock_t *lock) __acquires(lock);
unsigned long __lockfunc _raw_read_lock_irqsave(rwlock_t *lock)
- __acquires(lock);
+ __acquires_shared(lock);
unsigned long __lockfunc _raw_write_lock_irqsave(rwlock_t *lock)
__acquires(lock);
int __lockfunc _raw_read_trylock(rwlock_t *lock) __cond_acquires_shared(true, lock);
@@ -36,7 +36,7 @@ void __lockfunc _raw_read_unlock_irq(rwlock_t *lock) __releases_shared(lock);
void __lockfunc _raw_write_unlock_irq(rwlock_t *lock) __releases(lock);
void __lockfunc
_raw_read_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
- __releases(lock);
+ __releases_shared(lock);
void __lockfunc
_raw_write_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
__releases(lock);
@@ -116,6 +116,7 @@ _raw_write_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
#endif
static inline int __raw_read_trylock(rwlock_t *lock)
+ __cond_acquires_shared(true, lock)
{
preempt_disable();
if (do_raw_read_trylock(lock)) {
@@ -127,6 +128,7 @@ static inline int __raw_read_trylock(rwlock_t *lock)
}
static inline int __raw_write_trylock(rwlock_t *lock)
+ __cond_acquires(true, lock)
{
preempt_disable();
if (do_raw_write_trylock(lock)) {
diff --git a/include/linux/sched/deadline.h b/include/linux/sched/deadline.h
index c40115d4e34d..8b46bb607897 100644
--- a/include/linux/sched/deadline.h
+++ b/include/linux/sched/deadline.h
@@ -33,6 +33,15 @@ struct root_domain;
extern void dl_add_task_root_domain(struct task_struct *p);
extern void dl_clear_root_domain(struct root_domain *rd);
extern void dl_clear_root_domain_cpu(int cpu);
+/*
+ * Return whether moving DL task @p to @new_mask requires moving DL
+ * bandwidth accounting between root domains. This helper is specific to
+ * DL bandwidth move accounting semantics and is shared by
+ * cpuset_can_attach() and set_cpus_allowed_dl() so both paths use the
+ * same source root-domain test.
+ */
+extern bool dl_task_needs_bw_move(struct task_struct *p,
+ const struct cpumask *new_mask);
extern u64 dl_cookie;
extern bool dl_bw_visited(int cpu, u64 cookie);
diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
index a22248aebcf9..a4835a7de07e 100644
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -739,7 +739,7 @@ static inline int thread_group_empty(struct task_struct *p)
extern struct sighand_struct *lock_task_sighand(struct task_struct *task,
unsigned long *flags)
- __acquires(&task->sighand->siglock);
+ __cond_acquires(nonnull, &task->sighand->siglock);
static inline void unlock_task_sighand(struct task_struct *task,
unsigned long *flags)
diff --git a/include/linux/sched/topology.h b/include/linux/sched/topology.h
index 45c0022b91ce..6f8a4ae860da 100644
--- a/include/linux/sched/topology.h
+++ b/include/linux/sched/topology.h
@@ -141,18 +141,30 @@ struct sched_domain {
unsigned int span_weight;
/*
- * Span of all CPUs in this domain.
+ * See sched_domain_span(), on why flex arrays are broken.
*
- * NOTE: this field is variable length. (Allocated dynamically
- * by attaching extra space to the end of the structure,
- * depending on how many CPUs the kernel has booted up with)
- */
unsigned long span[];
+ */
};
static inline struct cpumask *sched_domain_span(struct sched_domain *sd)
{
- return to_cpumask(sd->span);
+ /*
+ * Turns out that C flexible arrays are fundamentally broken since it
+ * is allowed for offsetof(*sd, span) < sizeof(*sd), this means that
+ * structure initialzation *sd = { ... }; which writes every byte
+ * inside sizeof(*type), will over-write the start of the flexible
+ * array.
+ *
+ * Luckily, the way we allocate sched_domain is by:
+ *
+ * sizeof(*sd) + cpumask_size()
+ *
+ * this means that we have sufficient space for the whole flex array
+ * *outside* of sizeof(*sd). So use that, and avoid using sd->span.
+ */
+ unsigned long *bitmap = (void *)sd + sizeof(*sd);
+ return to_cpumask(bitmap);
}
extern void partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[],
diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index 5774e554c0f0..f54c708f4c50 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -28,6 +28,14 @@
.dtr = true, \
}
+#define SPI_MEM_DTR_OP_PACKED_CMD(__opcode, __addr, __buswidth) \
+ { \
+ .nbytes = 2, \
+ .opcode = __opcode << 8 | __addr, \
+ .buswidth = __buswidth, \
+ .dtr = true, \
+ }
+
#define SPI_MEM_OP_ADDR(__nbytes, __val, __buswidth) \
{ \
.nbytes = __nbytes, \
diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h
index e1e2f144af9b..241277cd34cf 100644
--- a/include/linux/spinlock.h
+++ b/include/linux/spinlock.h
@@ -178,7 +178,7 @@ do { \
#ifdef CONFIG_DEBUG_SPINLOCK
extern void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock);
- extern int do_raw_spin_trylock(raw_spinlock_t *lock);
+ extern int do_raw_spin_trylock(raw_spinlock_t *lock) __cond_acquires(true, lock);
extern void do_raw_spin_unlock(raw_spinlock_t *lock) __releases(lock);
#else
static inline void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock)
@@ -189,6 +189,7 @@ static inline void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock)
}
static inline int do_raw_spin_trylock(raw_spinlock_t *lock)
+ __cond_acquires(true, lock)
{
int ret = arch_spin_trylock(&(lock)->raw_lock);
diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h
index 1e84e71ca495..3a50976471d7 100644
--- a/include/linux/spinlock_up.h
+++ b/include/linux/spinlock_up.h
@@ -48,16 +48,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
lock->slock = 1;
}
-/*
- * Read-write spinlocks. No debug version.
- */
-#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0)
-#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0)
-#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; })
-#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; })
-#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0)
-#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0)
-
#else /* DEBUG_SPINLOCK */
#define arch_spin_is_locked(lock) ((void)(lock), 0)
/* for sched/core.c and kernel_lock.c: */
@@ -68,4 +58,14 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
#define arch_spin_is_contended(lock) (((void)(lock), 0))
+/*
+ * Read-write spinlocks. No debug version.
+ */
+#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0)
+#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0)
+#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; })
+#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; })
+#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0)
+#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0)
+
#endif /* __LINUX_SPINLOCK_UP_H */
diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h
index 72820503514c..01011113d226 100644
--- a/include/linux/stop_machine.h
+++ b/include/linux/stop_machine.h
@@ -99,7 +99,7 @@ static inline void print_stop_info(const char *log_lvl, struct task_struct *task
* stop_machine: freeze the machine on all CPUs and run this function
* @fn: the function to run
* @data: the data ptr to pass to @fn()
- * @cpus: the cpus to run @fn() on (NULL = run on each online CPU)
+ * @cpus: the cpus to run @fn() on (NULL = one unspecified online CPU)
*
* Description: This causes a thread to be scheduled on every CPU, which
* will run with interrupts disabled. Each CPU specified by @cpus will
@@ -133,7 +133,7 @@ int stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus);
* stop_machine_cpuslocked: freeze the machine on all CPUs and run this function
* @fn: the function to run
* @data: the data ptr to pass to @fn()
- * @cpus: the cpus to run @fn() on (NULL = run on each online CPU)
+ * @cpus: the cpus to run @fn() on (NULL = one unspecified online CPU)
*
* Same as above. Avoids nested calls to cpus_read_lock().
*
diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h
index eb4bd62df319..ab61bed2f7af 100644
--- a/include/linux/sunrpc/debug.h
+++ b/include/linux/sunrpc/debug.h
@@ -38,6 +38,8 @@ extern unsigned int nlm_debug;
do { \
ifdebug(fac) \
__sunrpc_printk(fmt, ##__VA_ARGS__); \
+ else \
+ no_printk(fmt, ##__VA_ARGS__); \
} while (0)
# define dfprintk_rcu(fac, fmt, ...) \
@@ -46,15 +48,15 @@ do { \
rcu_read_lock(); \
__sunrpc_printk(fmt, ##__VA_ARGS__); \
rcu_read_unlock(); \
+ } else { \
+ no_printk(fmt, ##__VA_ARGS__); \
} \
} while (0)
-# define RPC_IFDEBUG(x) x
#else
# define ifdebug(fac) if (0)
-# define dfprintk(fac, fmt, ...) do {} while (0)
-# define dfprintk_rcu(fac, fmt, ...) do {} while (0)
-# define RPC_IFDEBUG(x)
+# define dfprintk(fac, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
+# define dfprintk_rcu(fac, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
#endif
/*
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index ccba79ebf893..0dbdf3722537 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -95,10 +95,7 @@ struct rpc_task {
int tk_rpc_status; /* Result of last RPC operation */
unsigned short tk_flags; /* misc flags */
unsigned short tk_timeouts; /* maj timeouts */
-
-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) || IS_ENABLED(CONFIG_TRACEPOINTS)
unsigned short tk_pid; /* debugging aid */
-#endif
unsigned char tk_priority : 2,/* Task priority */
tk_garb_retry : 2,
tk_cred_retry : 2;
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 02bd6ddb6278..8787b3511c86 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -1283,12 +1283,8 @@ static inline long ksys_lchown(const char __user *filename, uid_t user,
AT_SYMLINK_NOFOLLOW);
}
-int do_sys_ftruncate(unsigned int fd, loff_t length, int small);
-
-static inline long ksys_ftruncate(unsigned int fd, loff_t length)
-{
- return do_sys_ftruncate(fd, length, 1);
-}
+#define FTRUNCATE_LFS (1u << 0) /* allow truncating > 32-bit */
+int ksys_ftruncate(unsigned int fd, loff_t length, unsigned int flags);
int do_sys_truncate(const char __user *pathname, loff_t length);
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index f72eef31fa23..c44cf9ae8d16 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -228,8 +228,7 @@ struct tcp_sock {
u32 sacked_out; /* SACK'd packets */
u16 tcp_header_len; /* Bytes of tcp header to send */
u8 scaling_ratio; /* see tcp_win_from_space() */
- u8 chrono_type : 2, /* current chronograph type */
- repair : 1,
+ u8 repair : 1,
tcp_usec_ts : 1, /* TSval values in usec */
is_sack_reneg:1, /* in recovery from loss with SACK reneg? */
is_cwnd_limited:1,/* forward progress limited by snd_cwnd? */
@@ -264,6 +263,7 @@ struct tcp_sock {
* total number of data bytes sent.
*/
u32 snd_sml; /* Last byte of the most recently transmitted small packet */
+ u8 chrono_type; /* current chronograph type */
u32 chrono_start; /* Start time in jiffies of a TCP chrono */
u32 chrono_stat[3]; /* Time in jiffies for chrono_stat stats */
u32 write_seq; /* Tail(+1) of data held in tcp send buffer */
diff --git a/include/linux/trace_printk.h b/include/linux/trace_printk.h
index bb5874097f24..2670ec7f4262 100644
--- a/include/linux/trace_printk.h
+++ b/include/linux/trace_printk.h
@@ -107,7 +107,6 @@ do { \
__trace_printk(_THIS_IP_, fmt, ##args); \
} while (0)
-extern __printf(2, 3)
int __trace_bprintk(unsigned long ip, const char *fmt, ...);
extern __printf(2, 3)
diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h
index 2bfe3baa63f4..782c42d25db1 100644
--- a/include/linux/vdpa.h
+++ b/include/linux/vdpa.h
@@ -72,9 +72,6 @@ struct vdpa_mgmt_dev;
* struct vdpa_device - representation of a vDPA device
* @dev: underlying device
* @vmap: the metadata passed to upper layer to be used for mapping
- * @driver_override: driver name to force a match; do not set directly,
- * because core frees it; use driver_set_override() to
- * set or clear it.
* @config: the configuration ops for this device.
* @map: the map ops for this device
* @cf_lock: Protects get and set access to configuration layout.
@@ -90,7 +87,6 @@ struct vdpa_mgmt_dev;
struct vdpa_device {
struct device dev;
union virtio_map vmap;
- const char *driver_override;
const struct vdpa_config_ops *config;
const struct virtio_map_ops *map;
struct rw_semaphore cf_lock; /* Protects get/set config */
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index e90859956514..ef02a4996d45 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -72,13 +72,11 @@ struct vfio_device {
u8 iommufd_attached:1;
#endif
u8 cdev_opened:1;
-#ifdef CONFIG_DEBUG_FS
/*
* debug_root is a static property of the vfio_device
* which must be set prior to registering the vfio_device.
*/
struct dentry *debug_root;
-#endif
};
/**
diff --git a/include/linux/wmi.h b/include/linux/wmi.h
index 75cb0c7cfe57..14fb644e1701 100644
--- a/include/linux/wmi.h
+++ b/include/linux/wmi.h
@@ -18,16 +18,12 @@
* struct wmi_device - WMI device structure
* @dev: Device associated with this WMI device
* @setable: True for devices implementing the Set Control Method
- * @driver_override: Driver name to force a match; do not set directly,
- * because core frees it; use driver_set_override() to
- * set or clear it.
*
* This represents WMI devices discovered by the WMI driver core.
*/
struct wmi_device {
struct device dev;
bool setable;
- const char *driver_override;
};
/**
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index a4749f56398f..218557a8f757 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -512,6 +512,28 @@ __printf(1, 4) struct workqueue_struct *
alloc_workqueue_noprof(const char *fmt, unsigned int flags, int max_active, ...);
#define alloc_workqueue(...) alloc_hooks(alloc_workqueue_noprof(__VA_ARGS__))
+/**
+ * devm_alloc_workqueue - Resource-managed allocate a workqueue
+ * @dev: Device to allocate workqueue for
+ * @fmt: printf format for the name of the workqueue
+ * @flags: WQ_* flags
+ * @max_active: max in-flight work items, 0 for default
+ * @...: args for @fmt
+ *
+ * Resource managed workqueue, see alloc_workqueue() for details.
+ *
+ * The workqueue will be automatically destroyed on driver detach. Typically
+ * this should be used in drivers already relying on devm interafaces.
+ *
+ * RETURNS:
+ * Pointer to the allocated workqueue on success, %NULL on failure.
+ */
+__printf(2, 5) struct workqueue_struct *
+devm_alloc_workqueue_noprof(struct device *dev, const char *fmt,
+ unsigned int flags, int max_active, ...);
+#define devm_alloc_workqueue(...) \
+ alloc_hooks(devm_alloc_workqueue_noprof(__VA_ARGS__))
+
#ifdef CONFIG_LOCKDEP
/**
* alloc_workqueue_lockdep_map - allocate a workqueue with user-defined lockdep_map
@@ -568,6 +590,8 @@ alloc_workqueue_lockdep_map(const char *fmt, unsigned int flags, int max_active,
*/
#define alloc_ordered_workqueue(fmt, flags, args...) \
alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args)
+#define devm_alloc_ordered_workqueue(dev, fmt, flags, args...) \
+ devm_alloc_workqueue(dev, fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args)
#define create_workqueue(name) \
alloc_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM | WQ_PERCPU, 1, (name))
diff --git a/include/linux/ww_mutex.h b/include/linux/ww_mutex.h
index 85b1fff02fde..0c95ead5a297 100644
--- a/include/linux/ww_mutex.h
+++ b/include/linux/ww_mutex.h
@@ -181,7 +181,7 @@ static inline void ww_acquire_init(struct ww_acquire_ctx *ctx,
* data structures.
*/
static inline void ww_acquire_done(struct ww_acquire_ctx *ctx)
- __releases(ctx) __acquires_shared(ctx) __no_context_analysis
+ __must_hold(ctx)
{
#ifdef DEBUG_WW_MUTEXES
lockdep_assert_held(ctx);
@@ -199,7 +199,7 @@ static inline void ww_acquire_done(struct ww_acquire_ctx *ctx)
* mutexes have been released with ww_mutex_unlock.
*/
static inline void ww_acquire_fini(struct ww_acquire_ctx *ctx)
- __releases_shared(ctx) __no_context_analysis
+ __releases(ctx) __no_context_analysis
{
#ifdef CONFIG_DEBUG_LOCK_ALLOC
mutex_release(&ctx->first_lock_dep_map, _THIS_IP_);
diff --git a/include/net/bond_3ad.h b/include/net/bond_3ad.h
index c92d4a976246..05572c19e14b 100644
--- a/include/net/bond_3ad.h
+++ b/include/net/bond_3ad.h
@@ -243,7 +243,7 @@ typedef struct port {
churn_state_t sm_churn_actor_state;
churn_state_t sm_churn_partner_state;
struct slave *slave; /* pointer to the bond slave that this port belongs to */
- struct aggregator *aggregator; /* pointer to an aggregator that this port related to */
+ struct aggregator __rcu *aggregator; /* pointer to an aggregator that this port related to */
struct port *next_port_in_aggregator; /* Next port on the linked list of the parent aggregator */
u32 transaction_id; /* continuous number for identification of Marker PDU's; */
struct lacpdu lacpdu; /* the lacpdu that will be sent for this port */
diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h
index a7b7abd66e21..880a5ec786cf 100644
--- a/include/net/dropreason-core.h
+++ b/include/net/dropreason-core.h
@@ -80,6 +80,7 @@
FN(UNHANDLED_PROTO) \
FN(SKB_CSUM) \
FN(SKB_GSO_SEG) \
+ FN(SKB_BAD_GSO) \
FN(SKB_UCOPY_FAULT) \
FN(DEV_HDR) \
FN(DEV_READY) \
@@ -130,6 +131,7 @@
FN(DUALPI2_STEP_DROP) \
FN(PSP_INPUT) \
FN(PSP_OUTPUT) \
+ FN(RECURSION_LIMIT) \
FNe(MAX)
/**
@@ -426,6 +428,8 @@ enum skb_drop_reason {
SKB_DROP_REASON_SKB_CSUM,
/** @SKB_DROP_REASON_SKB_GSO_SEG: gso segmentation error */
SKB_DROP_REASON_SKB_GSO_SEG,
+ /** @SKB_DROP_REASON_SKB_BAD_GSO: malicious gso packet. */
+ SKB_DROP_REASON_SKB_BAD_GSO,
/**
* @SKB_DROP_REASON_SKB_UCOPY_FAULT: failed to copy data from user space,
* e.g., via zerocopy_sg_from_iter() or skb_orphan_frags_rx()
@@ -622,6 +626,8 @@ enum skb_drop_reason {
SKB_DROP_REASON_PSP_INPUT,
/** @SKB_DROP_REASON_PSP_OUTPUT: PSP output checks failed */
SKB_DROP_REASON_PSP_OUTPUT,
+ /** @SKB_DROP_REASON_RECURSION_LIMIT: Dead loop on virtual device. */
+ SKB_DROP_REASON_RECURSION_LIMIT,
/**
* @SKB_DROP_REASON_MAX: the maximum of core drop reasons, which
* shouldn't be used as a real 'reason' - only for tracing code gen
diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h
index 359b595f1df9..b99805ee2fd1 100644
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -162,7 +162,7 @@ static inline void ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb,
dev->name);
DEV_STATS_INC(dev, tx_errors);
}
- kfree_skb(skb);
+ kfree_skb_reason(skb, SKB_DROP_REASON_RECURSION_LIMIT);
return;
}
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index ec8a8ec9c0aa..3ec41574af77 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -1216,12 +1216,15 @@ struct nft_stats {
struct u64_stats_sync syncp;
};
+#define NFT_HOOK_REMOVE (1 << 0)
+
struct nft_hook {
struct list_head list;
struct list_head ops_list;
struct rcu_head rcu;
char ifname[IFNAMSIZ];
u8 ifnamelen;
+ u8 flags;
};
struct nf_hook_ops *nft_hook_find_ops(const struct nft_hook *hook,
@@ -1676,6 +1679,16 @@ struct nft_trans {
u8 put_net:1;
};
+/**
+ * struct nft_trans_hook - nf_tables hook update in transaction
+ * @list: used internally
+ * @hook: struct nft_hook with the device hook
+ */
+struct nft_trans_hook {
+ struct list_head list;
+ struct nft_hook *hook;
+};
+
/**
* struct nft_trans_binding - nf_tables object with binding support in transaction
* @nft_trans: base structure, MUST be first member
diff --git a/include/net/pie.h b/include/net/pie.h
index 01cbc66825a4..1f3db0c35514 100644
--- a/include/net/pie.h
+++ b/include/net/pie.h
@@ -104,7 +104,7 @@ static inline void pie_vars_init(struct pie_vars *vars)
vars->dq_tstamp = DTIME_INVALID;
vars->accu_prob = 0;
vars->dq_count = DQCOUNT_INVALID;
- vars->avg_dq_rate = 0;
+ WRITE_ONCE(vars->avg_dq_rate, 0);
}
static inline struct pie_skb_cb *get_pie_cb(const struct sk_buff *skb)
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index c3d657359a3d..5fc0b1ebaf25 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -1170,12 +1170,22 @@ static inline void tcf_kfree_skb_list(struct sk_buff *skb)
static inline void qdisc_dequeue_drop(struct Qdisc *q, struct sk_buff *skb,
enum skb_drop_reason reason)
{
+ struct Qdisc *root;
+
DEBUG_NET_WARN_ON_ONCE(!(q->flags & TCQ_F_DEQUEUE_DROPS));
DEBUG_NET_WARN_ON_ONCE(q->flags & TCQ_F_NOLOCK);
- tcf_set_drop_reason(skb, reason);
- skb->next = q->to_free;
- q->to_free = skb;
+ rcu_read_lock();
+ root = qdisc_root_sleeping(q);
+
+ if (root->flags & TCQ_F_DEQUEUE_DROPS) {
+ tcf_set_drop_reason(skb, reason);
+ skb->next = root->to_free;
+ root->to_free = skb;
+ } else {
+ kfree_skb_reason(skb, reason);
+ }
+ rcu_read_unlock();
}
/* Instead of calling kfree_skb() while root qdisc lock is held,
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 978eea2d5df0..ebc72dce4134 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1465,7 +1465,7 @@ static inline u32 tcp_snd_cwnd(const struct tcp_sock *tp)
static inline void tcp_snd_cwnd_set(struct tcp_sock *tp, u32 val)
{
WARN_ON_ONCE((int)val <= 0);
- tp->snd_cwnd = val;
+ WRITE_ONCE(tp->snd_cwnd, val);
}
static inline bool tcp_in_slow_start(const struct tcp_sock *tp)
@@ -2156,7 +2156,34 @@ enum tcp_chrono {
__TCP_CHRONO_MAX,
};
-void tcp_chrono_start(struct sock *sk, const enum tcp_chrono type);
+static inline void tcp_chrono_set(struct tcp_sock *tp, const enum tcp_chrono new)
+{
+ const u32 now = tcp_jiffies32;
+ enum tcp_chrono old = tp->chrono_type;
+
+ /* Following WRITE_ONCE()s pair with READ_ONCE()s in
+ * tcp_get_info_chrono_stats().
+ */
+ if (old > TCP_CHRONO_UNSPEC)
+ WRITE_ONCE(tp->chrono_stat[old - 1],
+ tp->chrono_stat[old - 1] + now - tp->chrono_start);
+ WRITE_ONCE(tp->chrono_start, now);
+ WRITE_ONCE(tp->chrono_type, new);
+}
+
+static inline void tcp_chrono_start(struct sock *sk, const enum tcp_chrono type)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+
+ /* If there are multiple conditions worthy of tracking in a
+ * chronograph then the highest priority enum takes precedence
+ * over the other conditions. So that if something "more interesting"
+ * starts happening, stop the previous chrono and start a new one.
+ */
+ if (type > tp->chrono_type)
+ tcp_chrono_set(tp, type);
+}
+
void tcp_chrono_stop(struct sock *sk, const enum tcp_chrono type);
/* This helper is needed, because skb->tcp_tsorted_anchor uses
diff --git a/include/net/tcp_ecn.h b/include/net/tcp_ecn.h
index e9a933641636..865d5c5a7718 100644
--- a/include/net/tcp_ecn.h
+++ b/include/net/tcp_ecn.h
@@ -181,7 +181,7 @@ static inline void tcp_accecn_third_ack(struct sock *sk,
tcp_accecn_validate_syn_feedback(sk, ace, sent_ect)) {
if ((tcp_accecn_extract_syn_ect(ace) == INET_ECN_CE) &&
!tp->delivered_ce)
- tp->delivered_ce++;
+ WRITE_ONCE(tp->delivered_ce, 1);
}
break;
}
diff --git a/include/rdma/ib_umem.h b/include/rdma/ib_umem.h
index 0a8e092c0ea8..e426d451b893 100644
--- a/include/rdma/ib_umem.h
+++ b/include/rdma/ib_umem.h
@@ -22,6 +22,7 @@ struct ib_umem {
u64 iova;
size_t length;
unsigned long address;
+ unsigned long dma_attrs;
u32 writable : 1;
u32 is_odp : 1;
u32 is_dmabuf : 1;
diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h
index 2a2b74b24a60..0435ba376369 100644
--- a/include/sound/soc-component.h
+++ b/include/sound/soc-component.h
@@ -90,6 +90,10 @@ struct snd_soc_component_driver {
struct snd_soc_pcm_runtime *rtd);
void (*pcm_destruct)(struct snd_soc_component *component,
struct snd_pcm *pcm);
+ int (*pcm_new)(struct snd_soc_component *component,
+ struct snd_soc_pcm_runtime *rtd);
+ void (*pcm_free)(struct snd_soc_component *component,
+ struct snd_pcm *pcm);
/* component wide operations */
int (*set_sysclk)(struct snd_soc_component *component,
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 7d8376c8e1be..1e0b7cd8d956 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -1412,6 +1412,9 @@ struct snd_soc_dai *snd_soc_find_dai(
struct snd_soc_dai *snd_soc_find_dai_with_mutex(
const struct snd_soc_dai_link_component *dlc);
+void soc_pcm_set_dai_params(struct snd_soc_dai *dai,
+ struct snd_pcm_hw_params *params);
+
#include <sound/soc-dai.h>
static inline
diff --git a/include/trace/events/dma_fence.h b/include/trace/events/dma_fence.h
index 4814a65b68dc..3abba45c0601 100644
--- a/include/trace/events/dma_fence.h
+++ b/include/trace/events/dma_fence.h
@@ -9,37 +9,12 @@
struct dma_fence;
-DECLARE_EVENT_CLASS(dma_fence,
-
- TP_PROTO(struct dma_fence *fence),
-
- TP_ARGS(fence),
-
- TP_STRUCT__entry(
- __string(driver, dma_fence_driver_name(fence))
- __string(timeline, dma_fence_timeline_name(fence))
- __field(unsigned int, context)
- __field(unsigned int, seqno)
- ),
-
- TP_fast_assign(
- __assign_str(driver);
- __assign_str(timeline);
- __entry->context = fence->context;
- __entry->seqno = fence->seqno;
- ),
-
- TP_printk("driver=%s timeline=%s context=%u seqno=%u",
- __get_str(driver), __get_str(timeline), __entry->context,
- __entry->seqno)
-);
-
/*
* Safe only for call sites which are guaranteed to not race with fence
* signaling,holding the fence->lock and having checked for not signaled, or the
* signaling path itself.
*/
-DECLARE_EVENT_CLASS(dma_fence_unsignaled,
+DECLARE_EVENT_CLASS(dma_fence,
TP_PROTO(struct dma_fence *fence),
@@ -64,14 +39,14 @@ DECLARE_EVENT_CLASS(dma_fence_unsignaled,
__entry->seqno)
);
-DEFINE_EVENT(dma_fence_unsignaled, dma_fence_emit,
+DEFINE_EVENT(dma_fence, dma_fence_emit,
TP_PROTO(struct dma_fence *fence),
TP_ARGS(fence)
);
-DEFINE_EVENT(dma_fence_unsignaled, dma_fence_init,
+DEFINE_EVENT(dma_fence, dma_fence_init,
TP_PROTO(struct dma_fence *fence),
@@ -85,14 +60,14 @@ DEFINE_EVENT(dma_fence, dma_fence_destroy,
TP_ARGS(fence)
);
-DEFINE_EVENT(dma_fence_unsignaled, dma_fence_enable_signal,
+DEFINE_EVENT(dma_fence, dma_fence_enable_signal,
TP_PROTO(struct dma_fence *fence),
TP_ARGS(fence)
);
-DEFINE_EVENT(dma_fence_unsignaled, dma_fence_signaled,
+DEFINE_EVENT(dma_fence, dma_fence_signaled,
TP_PROTO(struct dma_fence *fence),
diff --git a/include/trace/events/mptcp.h b/include/trace/events/mptcp.h
index 269d949b2025..04521acba483 100644
--- a/include/trace/events/mptcp.h
+++ b/include/trace/events/mptcp.h
@@ -219,7 +219,7 @@ TRACE_EVENT(mptcp_rcvbuf_grow,
__be32 *p32;
__entry->time = time;
- __entry->rtt_us = msk->rcvq_space.rtt_us >> 3;
+ __entry->rtt_us = mptcp_rtt_us_est(msk) >> 3;
__entry->copied = msk->rcvq_space.copied;
__entry->inq = mptcp_inq_hint(sk);
__entry->space = msk->rcvq_space.space;
diff --git a/include/trace/events/net.h b/include/trace/events/net.h
index fdd9ad474ce3..dbc2c5598e35 100644
--- a/include/trace/events/net.h
+++ b/include/trace/events/net.h
@@ -10,6 +10,7 @@
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/tracepoint.h>
+#include <net/busy_poll.h>
TRACE_EVENT(net_dev_start_xmit,
@@ -208,7 +209,8 @@ DECLARE_EVENT_CLASS(net_dev_rx_verbose_template,
TP_fast_assign(
__assign_str(name);
#ifdef CONFIG_NET_RX_BUSY_POLL
- __entry->napi_id = skb->napi_id;
+ __entry->napi_id = napi_id_valid(skb->napi_id) ?
+ skb->napi_id : 0;
#else
__entry->napi_id = 0;
#endif
diff --git a/include/trace/events/timer.h b/include/trace/events/timer.h
index 1641ae3e6ca0..ab9a9386f7b6 100644
--- a/include/trace/events/timer.h
+++ b/include/trace/events/timer.h
@@ -218,12 +218,13 @@ TRACE_EVENT(hrtimer_setup,
* hrtimer_start - called when the hrtimer is started
* @hrtimer: pointer to struct hrtimer
* @mode: the hrtimers mode
+ * @was_armed: Was armed when hrtimer_start*() was invoked
*/
TRACE_EVENT(hrtimer_start,
- TP_PROTO(struct hrtimer *hrtimer, enum hrtimer_mode mode),
+ TP_PROTO(struct hrtimer *hrtimer, enum hrtimer_mode mode, bool was_armed),
- TP_ARGS(hrtimer, mode),
+ TP_ARGS(hrtimer, mode, was_armed),
TP_STRUCT__entry(
__field( void *, hrtimer )
@@ -231,6 +232,7 @@ TRACE_EVENT(hrtimer_start,
__field( s64, expires )
__field( s64, softexpires )
__field( enum hrtimer_mode, mode )
+ __field( bool, was_armed )
),
TP_fast_assign(
@@ -239,13 +241,14 @@ TRACE_EVENT(hrtimer_start,
__entry->expires = hrtimer_get_expires(hrtimer);
__entry->softexpires = hrtimer_get_softexpires(hrtimer);
__entry->mode = mode;
+ __entry->was_armed = was_armed;
),
TP_printk("hrtimer=%p function=%ps expires=%llu softexpires=%llu "
- "mode=%s", __entry->hrtimer, __entry->function,
+ "mode=%s was_armed=%d", __entry->hrtimer, __entry->function,
(unsigned long long) __entry->expires,
(unsigned long long) __entry->softexpires,
- decode_hrtimer_mode(__entry->mode))
+ decode_hrtimer_mode(__entry->mode), __entry->was_armed)
);
/**
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index e9b5f79e1ee1..83a96c56b8ca 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -1568,6 +1568,8 @@ enum {
IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE,
IFLA_BOND_SLAVE_PRIO,
IFLA_BOND_SLAVE_ACTOR_PORT_PRIO,
+ IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE,
+ IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE,
__IFLA_BOND_SLAVE_MAX,
};
diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
index 1dafbc552d37..f63edbe71d54 100644
--- a/include/uapi/linux/iommufd.h
+++ b/include/uapi/linux/iommufd.h
@@ -1052,6 +1052,11 @@ struct iommu_fault_alloc {
enum iommu_viommu_type {
IOMMU_VIOMMU_TYPE_DEFAULT = 0,
IOMMU_VIOMMU_TYPE_ARM_SMMUV3 = 1,
+ /*
+ * TEGRA241_CMDQV requirements (otherwise, VCMDQs will not work)
+ * - Kernel will allocate a VINTF (HYP_OWN=0) to back this VIOMMU. So,
+ * VMM must wire the HYP_OWN bit to 0 in guest VINTF_CONFIG register
+ */
IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV = 2,
};
diff --git a/include/uapi/linux/mii.h b/include/uapi/linux/mii.h
index 39f7c44baf53..61d6edad4b94 100644
--- a/include/uapi/linux/mii.h
+++ b/include/uapi/linux/mii.h
@@ -82,7 +82,8 @@
#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */
#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */
-#define ADVERTISE_RESV 0x1000 /* Unused... */
+#define ADVERTISE_XNP 0x1000 /* Extended Next Page */
+#define ADVERTISE_RESV ADVERTISE_XNP /* Used to be reserved */
#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */
#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */
#define ADVERTISE_NPAGE 0x8000 /* Next page bit */
diff --git a/io_uring/io-wq.c b/io_uring/io-wq.c
index 7a9f94a0ce6f..8cc7b47d3089 100644
--- a/io_uring/io-wq.c
+++ b/io_uring/io-wq.c
@@ -1124,7 +1124,8 @@ static inline void io_wq_remove_pending(struct io_wq *wq,
if (io_wq_is_hashed(work) && work == wq->hash_tail[hash]) {
if (prev)
prev_work = container_of(prev, struct io_wq_work, list);
- if (prev_work && io_get_work_hash(prev_work) == hash)
+ if (prev_work && io_wq_is_hashed(prev_work) &&
+ io_get_work_hash(prev_work) == hash)
wq->hash_tail[hash] = prev_work;
else
wq->hash_tail[hash] = NULL;
diff --git a/io_uring/napi.c b/io_uring/napi.c
index 4a10de03e426..8d68366a4b90 100644
--- a/io_uring/napi.c
+++ b/io_uring/napi.c
@@ -276,6 +276,8 @@ static int io_napi_register_napi(struct io_ring_ctx *ctx,
/* clean the napi list for new settings */
io_napi_free(ctx);
WRITE_ONCE(ctx->napi_track_mode, napi->op_param);
+ /* cap NAPI at 10 msec of spin time */
+ napi->busy_poll_to = min(10000, napi->busy_poll_to);
WRITE_ONCE(ctx->napi_busy_poll_dt, napi->busy_poll_to * NSEC_PER_USEC);
WRITE_ONCE(ctx->napi_prefer_busy_poll, !!napi->prefer_busy_poll);
return 0;
diff --git a/kernel/audit.c b/kernel/audit.c
index 5a0216056524..d3a8268998d7 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1466,6 +1466,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
err = audit_list_rules_send(skb, seq);
break;
case AUDIT_TRIM:
+ if (audit_enabled == AUDIT_LOCKED)
+ return -EPERM;
audit_trim_trees();
audit_log_common_recv_msg(audit_context(), &ab,
AUDIT_CONFIG_CHANGE);
@@ -1478,6 +1480,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
size_t msglen = data_len;
char *old, *new;
+ if (audit_enabled == AUDIT_LOCKED)
+ return -EPERM;
err = -EINVAL;
if (msglen < 2 * sizeof(u32))
break;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index f6af6a8f68c4..bd4c65775c35 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2786,7 +2786,7 @@ void __audit_log_capset(const struct cred *new, const struct cred *old)
context->capset.pid = task_tgid_nr(current);
context->capset.cap.effective = new->cap_effective;
- context->capset.cap.inheritable = new->cap_effective;
+ context->capset.cap.inheritable = new->cap_inheritable;
context->capset.cap.permitted = new->cap_permitted;
context->capset.cap.ambient = new->cap_ambient;
context->type = AUDIT_CAPSET;
diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c
index 9c68c9b0b24a..523c3a61063b 100644
--- a/kernel/bpf/arena.c
+++ b/kernel/bpf/arena.c
@@ -562,6 +562,10 @@ static long arena_alloc_pages(struct bpf_arena *arena, long uaddr, long page_cnt
u32 uaddr32;
int ret, i;
+ if (node_id != NUMA_NO_NODE &&
+ ((unsigned int)node_id >= nr_node_ids || !node_online(node_id)))
+ return 0;
+
if (page_cnt > page_cnt_max)
return 0;
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 33de68c95ad8..5e25e0353509 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -1015,8 +1015,10 @@ static void bpf_fd_array_map_clear(struct bpf_map *map, bool need_defer)
struct bpf_array *array = container_of(map, struct bpf_array, map);
int i;
- for (i = 0; i < array->map.max_entries; i++)
+ for (i = 0; i < array->map.max_entries; i++) {
__fd_array_map_delete_elem(map, &i, need_defer);
+ cond_resched();
+ }
}
static void prog_array_map_seq_show_elem(struct bpf_map *map, void *key,
diff --git a/kernel/bpf/bpf_local_storage.c b/kernel/bpf/bpf_local_storage.c
index 9c96a4477f81..4c6079d2cf28 100644
--- a/kernel/bpf/bpf_local_storage.c
+++ b/kernel/bpf/bpf_local_storage.c
@@ -393,6 +393,9 @@ int bpf_selem_unlink(struct bpf_local_storage_elem *selem)
unsigned long flags;
int err;
+ if (in_nmi())
+ return -EOPNOTSUPP;
+
if (unlikely(!selem_linked_to_storage_lockless(selem)))
/* selem has already been unlinked from sk */
return 0;
diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
index 0c4a0c8e6f70..0aa9378fae4f 100644
--- a/kernel/bpf/bpf_lsm.c
+++ b/kernel/bpf/bpf_lsm.c
@@ -359,8 +359,6 @@ BTF_ID(func, bpf_lsm_sb_umount)
BTF_ID(func, bpf_lsm_settime)
#ifdef CONFIG_SECURITY_NETWORK
-BTF_ID(func, bpf_lsm_inet_conn_established)
-
BTF_ID(func, bpf_lsm_socket_accept)
BTF_ID(func, bpf_lsm_socket_bind)
BTF_ID(func, bpf_lsm_socket_connect)
@@ -381,7 +379,6 @@ BTF_ID(func, bpf_lsm_syslog)
BTF_ID(func, bpf_lsm_task_alloc)
BTF_ID(func, bpf_lsm_task_prctl)
BTF_ID(func, bpf_lsm_task_setscheduler)
-BTF_ID(func, bpf_lsm_task_to_inode)
BTF_ID(func, bpf_lsm_userns_create)
BTF_SET_END(sleepable_lsm_hooks)
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 71f9143fe90f..63d075f37459 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -9019,7 +9019,7 @@ static int btf_check_dtor_kfuncs(struct btf *btf, const struct btf_id_dtor_kfunc
if (!t || !btf_type_is_ptr(t))
return -EINVAL;
- if (IS_ENABLED(CONFIG_CFI_CLANG)) {
+ if (IS_ENABLED(CONFIG_CFI)) {
/* Ensure the destructor kfunc type matches btf_dtor_kfunc_t */
t = btf_type_by_id(btf, t->type);
if (!btf_type_is_void(t))
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 7b675a451ec8..048d275accae 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -1487,6 +1487,8 @@ void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other)
* know whether fp here is the clone or the original.
*/
fp->aux->prog = fp;
+ if (fp->aux->offload)
+ fp->aux->offload->prog = fp;
bpf_prog_clone_free(fp_other);
}
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index 3d619d01088e..cc0a43ebab6b 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -665,7 +665,7 @@ int dev_map_enqueue_multi(struct xdp_frame *xdpf, struct net_device *dev_rx,
for (i = 0; i < dtab->n_buckets; i++) {
head = dev_map_index_hash(dtab, i);
hlist_for_each_entry_rcu(dst, head, index_hlist,
- lockdep_is_held(&dtab->index_lock)) {
+ rcu_read_lock_bh_held()) {
if (!is_valid_dst(dst, xdpf))
continue;
@@ -747,7 +747,6 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb,
struct bpf_dtab_netdev *dst, *last_dst = NULL;
int excluded_devices[1+MAX_NEST_DEV];
struct hlist_head *head;
- struct hlist_node *next;
int num_excluded = 0;
unsigned int i;
int err;
@@ -787,7 +786,7 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb,
} else { /* BPF_MAP_TYPE_DEVMAP_HASH */
for (i = 0; i < dtab->n_buckets; i++) {
head = dev_map_index_hash(dtab, i);
- hlist_for_each_entry_safe(dst, next, head, index_hlist) {
+ hlist_for_each_entry_rcu(dst, head, index_hlist, rcu_read_lock_bh_held()) {
if (is_ifindex_excluded(excluded_devices, num_excluded,
dst->dev->ifindex))
continue;
diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
index bc6bc8bb871d..3dd9b4924ae4 100644
--- a/kernel/bpf/hashtab.c
+++ b/kernel/bpf/hashtab.c
@@ -1056,7 +1056,7 @@ static void pcpu_init_value(struct bpf_htab *htab, void __percpu *pptr,
for_each_possible_cpu(cpu) {
if (cpu == current_cpu)
- copy_map_value_long(&htab->map, per_cpu_ptr(pptr, cpu), value);
+ copy_map_value(&htab->map, per_cpu_ptr(pptr, cpu), value);
else /* Since elem is preallocated, we cannot touch special fields */
zero_map_value(&htab->map, per_cpu_ptr(pptr, cpu));
}
@@ -1138,6 +1138,10 @@ static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key,
} else if (fd_htab_map_needs_adjust(htab)) {
size = round_up(size, 8);
memcpy(htab_elem_value(l_new, key_size), value, size);
+ } else if (map_flags & BPF_F_LOCK) {
+ copy_map_value_locked(&htab->map,
+ htab_elem_value(l_new, key_size),
+ value, false);
} else {
copy_map_value(&htab->map, htab_elem_value(l_new, key_size), value);
}
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 6eb6c82ed2ee..d51f1b612f1d 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -845,7 +845,13 @@ int bpf_bprintf_prepare(const char *fmt, u32 fmt_size, const u64 *raw_args,
data->buf = buffers->buf;
for (i = 0; i < fmt_size; i++) {
- if ((!isprint(fmt[i]) && !isspace(fmt[i])) || !isascii(fmt[i])) {
+ unsigned char c = fmt[i];
+
+ /*
+ * Permit bytes >= 0x80 in plain text so UTF-8 literals can pass
+ * through unchanged, while still rejecting ASCII control bytes.
+ */
+ if (isascii(c) && !isprint(c) && !isspace(c)) {
err = -EINVAL;
goto out;
}
@@ -867,6 +873,15 @@ int bpf_bprintf_prepare(const char *fmt, u32 fmt_size, const u64 *raw_args,
* always access fmt[i + 1], in the worst case it will be a 0
*/
i++;
+ c = fmt[i];
+ /*
+ * The format parser below only understands ASCII conversion
+ * specifiers and modifiers, so reject non-ASCII after '%'.
+ */
+ if (!isascii(c)) {
+ err = -EINVAL;
+ goto out;
+ }
/* skip optional "[0 +-][num]" width formatting field */
while (fmt[i] == '0' || fmt[i] == '+' || fmt[i] == '-' ||
diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c
index 8fca0c64f7b1..23267213a17f 100644
--- a/kernel/bpf/local_storage.c
+++ b/kernel/bpf/local_storage.c
@@ -270,7 +270,7 @@ static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key,
goto enoent;
storage = list_next_entry(storage, list_map);
- if (!storage)
+ if (list_entry_is_head(storage, &map->list, list_map))
goto enoent;
} else {
storage = list_first_entry(&map->list,
diff --git a/kernel/bpf/offload.c b/kernel/bpf/offload.c
index 0ad97d643bf4..0d6f5569588c 100644
--- a/kernel/bpf/offload.c
+++ b/kernel/bpf/offload.c
@@ -435,9 +435,8 @@ static struct ns_common *bpf_prog_offload_info_fill_ns(void *private_data)
if (aux->offload) {
args->info->ifindex = aux->offload->netdev->ifindex;
- net = dev_net(aux->offload->netdev);
- get_net(net);
- ns = &net->ns;
+ net = maybe_get_net(dev_net(aux->offload->netdev));
+ ns = net ? &net->ns : NULL;
} else {
args->info->ifindex = 0;
ns = NULL;
@@ -647,9 +646,8 @@ static struct ns_common *bpf_map_offload_info_fill_ns(void *private_data)
if (args->offmap->netdev) {
args->info->ifindex = args->offmap->netdev->ifindex;
- net = dev_net(args->offmap->netdev);
- get_net(net);
- ns = &net->ns;
+ net = maybe_get_net(dev_net(args->offmap->netdev));
+ ns = net ? &net->ns : NULL;
} else {
args->info->ifindex = 0;
ns = NULL;
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 700938782bed..ed595159f1c5 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -3754,6 +3754,23 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
tr = prog->aux->dst_trampoline;
tgt_prog = prog->aux->dst_prog;
}
+ /*
+ * It is to prevent modifying struct pt_regs via kprobe_write_ctx=true
+ * freplace prog. Without this check, kprobe_write_ctx=true freplace
+ * prog is allowed to attach to kprobe_write_ctx=false kprobe prog, and
+ * then modify the registers of the kprobe prog's target kernel
+ * function.
+ *
+ * This also blocks the combination of uprobe+freplace, because it is
+ * unable to recognize the use of the tgt_prog as an uprobe or a kprobe
+ * by tgt_prog itself. At attach time, uprobe/kprobe is recognized by
+ * the target perf event flags in __perf_event_set_bpf_prog().
+ */
+ if (prog->type == BPF_PROG_TYPE_EXT &&
+ prog->aux->kprobe_write_ctx != tgt_prog->aux->kprobe_write_ctx) {
+ err = -EINVAL;
+ goto out_unlock;
+ }
err = bpf_link_prime(&link->link.link, &link_primer);
if (err)
diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c
index 98d9b4c0daff..e791ae065c39 100644
--- a/kernel/bpf/task_iter.c
+++ b/kernel/bpf/task_iter.c
@@ -9,6 +9,8 @@
#include <linux/bpf_mem_alloc.h>
#include <linux/btf_ids.h>
#include <linux/mm_types.h>
+#include <linux/mmap_lock.h>
+#include <linux/sched/mm.h>
#include "mmap_unlock_work.h"
static const char * const iter_task_type_names[] = {
@@ -794,11 +796,20 @@ const struct bpf_func_proto bpf_find_vma_proto = {
.arg5_type = ARG_ANYTHING,
};
+static inline void bpf_iter_mmput_async(struct mm_struct *mm)
+{
+#ifdef CONFIG_MMU
+ mmput_async(mm);
+#else
+ mmput(mm);
+#endif
+}
+
struct bpf_iter_task_vma_kern_data {
struct task_struct *task;
struct mm_struct *mm;
- struct mmap_unlock_irq_work *work;
- struct vma_iterator vmi;
+ struct vm_area_struct snapshot;
+ u64 next_addr;
};
struct bpf_iter_task_vma {
@@ -819,12 +830,28 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it,
struct task_struct *task, u64 addr)
{
struct bpf_iter_task_vma_kern *kit = (void *)it;
- bool irq_work_busy = false;
int err;
BUILD_BUG_ON(sizeof(struct bpf_iter_task_vma_kern) != sizeof(struct bpf_iter_task_vma));
BUILD_BUG_ON(__alignof__(struct bpf_iter_task_vma_kern) != __alignof__(struct bpf_iter_task_vma));
+ if (!IS_ENABLED(CONFIG_PER_VMA_LOCK)) {
+ kit->data = NULL;
+ return -EOPNOTSUPP;
+ }
+
+ /*
+ * Reject irqs-disabled contexts including NMI. Operations used
+ * by _next() and _destroy() (vma_end_read, fput, bpf_iter_mmput_async)
+ * can take spinlocks with IRQs disabled (pi_lock, pool->lock).
+ * Running from NMI or from a tracepoint that fires with those
+ * locks held could deadlock.
+ */
+ if (irqs_disabled()) {
+ kit->data = NULL;
+ return -EBUSY;
+ }
+
/* is_iter_reg_valid_uninit guarantees that kit hasn't been initialized
* before, so non-NULL kit->data doesn't point to previously
* bpf_mem_alloc'd bpf_iter_task_vma_kern_data
@@ -834,38 +861,131 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it,
return -ENOMEM;
kit->data->task = get_task_struct(task);
+ /*
+ * Safely read task->mm and acquire an mm reference.
+ *
+ * Cannot use get_task_mm() because its task_lock() is a
+ * blocking spin_lock that would deadlock if the target task
+ * already holds alloc_lock on this CPU (e.g. a softirq BPF
+ * program iterating a task interrupted while holding its
+ * alloc_lock).
+ */
+ if (!spin_trylock(&task->alloc_lock)) {
+ err = -EBUSY;
+ goto err_cleanup_iter;
+ }
kit->data->mm = task->mm;
+ if (kit->data->mm && !(task->flags & PF_KTHREAD))
+ mmget(kit->data->mm);
+ else
+ kit->data->mm = NULL;
+ spin_unlock(&task->alloc_lock);
if (!kit->data->mm) {
err = -ENOENT;
goto err_cleanup_iter;
}
- /* kit->data->work == NULL is valid after bpf_mmap_unlock_get_irq_work */
- irq_work_busy = bpf_mmap_unlock_get_irq_work(&kit->data->work);
- if (irq_work_busy || !mmap_read_trylock(kit->data->mm)) {
- err = -EBUSY;
- goto err_cleanup_iter;
- }
-
- vma_iter_init(&kit->data->vmi, kit->data->mm, addr);
+ kit->data->snapshot.vm_file = NULL;
+ kit->data->next_addr = addr;
return 0;
err_cleanup_iter:
- if (kit->data->task)
- put_task_struct(kit->data->task);
+ put_task_struct(kit->data->task);
bpf_mem_free(&bpf_global_ma, kit->data);
/* NULL kit->data signals failed bpf_iter_task_vma initialization */
kit->data = NULL;
return err;
}
+/*
+ * Find and lock the next VMA at or after data->next_addr.
+ *
+ * lock_vma_under_rcu() is a point lookup (mas_walk): it finds the VMA
+ * containing a given address but cannot iterate. An RCU-protected
+ * maple tree walk with vma_next() (mas_find) is needed first to locate
+ * the next VMA's vm_start across any gap.
+ *
+ * Between the RCU walk and the lock, the VMA may be removed, shrunk,
+ * or write-locked. On failure, advance past it using vm_end from the
+ * RCU walk. SLAB_TYPESAFE_BY_RCU can make vm_end stale, so fall back
+ * to PAGE_SIZE advancement to guarantee forward progress.
+ */
+static struct vm_area_struct *
+bpf_iter_task_vma_find_next(struct bpf_iter_task_vma_kern_data *data)
+{
+ struct vm_area_struct *vma;
+ struct vma_iterator vmi;
+ unsigned long start, end;
+
+retry:
+ rcu_read_lock();
+ vma_iter_init(&vmi, data->mm, data->next_addr);
+ vma = vma_next(&vmi);
+ if (!vma) {
+ rcu_read_unlock();
+ return NULL;
+ }
+ start = vma->vm_start;
+ end = vma->vm_end;
+ rcu_read_unlock();
+
+ vma = lock_vma_under_rcu(data->mm, start);
+ if (!vma) {
+ if (end <= data->next_addr)
+ data->next_addr += PAGE_SIZE;
+ else
+ data->next_addr = end;
+ goto retry;
+ }
+
+ if (unlikely(vma->vm_end <= data->next_addr)) {
+ data->next_addr += PAGE_SIZE;
+ vma_end_read(vma);
+ goto retry;
+ }
+
+ return vma;
+}
+
+static void bpf_iter_task_vma_snapshot_reset(struct vm_area_struct *snap)
+{
+ if (snap->vm_file) {
+ fput(snap->vm_file);
+ snap->vm_file = NULL;
+ }
+}
+
__bpf_kfunc struct vm_area_struct *bpf_iter_task_vma_next(struct bpf_iter_task_vma *it)
{
struct bpf_iter_task_vma_kern *kit = (void *)it;
+ struct vm_area_struct *snap, *vma;
if (!kit->data) /* bpf_iter_task_vma_new failed */
return NULL;
- return vma_next(&kit->data->vmi);
+
+ snap = &kit->data->snapshot;
+
+ bpf_iter_task_vma_snapshot_reset(snap);
+
+ vma = bpf_iter_task_vma_find_next(kit->data);
+ if (!vma)
+ return NULL;
+
+ memcpy(snap, vma, sizeof(*snap));
+
+ /*
+ * The verifier only trusts vm_mm and vm_file (see
+ * BTF_TYPE_SAFE_TRUSTED_OR_NULL in verifier.c). Take a reference
+ * on vm_file; vm_mm is already correct because lock_vma_under_rcu()
+ * verifies vma->vm_mm == mm. All other pointers are untrusted by
+ * the verifier and left as-is.
+ */
+ if (snap->vm_file)
+ get_file(snap->vm_file);
+
+ kit->data->next_addr = vma->vm_end;
+ vma_end_read(vma);
+ return snap;
}
__bpf_kfunc void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it)
@@ -873,8 +993,9 @@ __bpf_kfunc void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it)
struct bpf_iter_task_vma_kern *kit = (void *)it;
if (kit->data) {
- bpf_mmap_unlock_mm(kit->data->work, kit->data->mm);
+ bpf_iter_task_vma_snapshot_reset(&kit->data->snapshot);
put_task_struct(kit->data->task);
+ bpf_iter_mmput_async(kit->data->mm);
bpf_mem_free(&bpf_global_ma, kit->data);
}
}
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index e3814152b52f..77ddd452b803 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -5241,6 +5241,18 @@ static void check_fastcall_stack_contract(struct bpf_verifier_env *env,
}
}
+static void scrub_special_slot(struct bpf_func_state *state, int spi)
+{
+ int i;
+
+ /* regular write of data into stack destroys any spilled ptr */
+ state->stack[spi].spilled_ptr.type = NOT_INIT;
+ /* Mark slots as STACK_MISC if they belonged to spilled ptr/dynptr/iter. */
+ if (is_stack_slot_special(&state->stack[spi]))
+ for (i = 0; i < BPF_REG_SIZE; i++)
+ scrub_spilled_slot(&state->stack[spi].slot_type[i]);
+}
+
/* check_stack_{read,write}_fixed_off functions track spill/fill of registers,
* stack boundary and alignment are checked in check_mem_access()
*/
@@ -5338,12 +5350,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
} else {
u8 type = STACK_MISC;
- /* regular write of data into stack destroys any spilled ptr */
- state->stack[spi].spilled_ptr.type = NOT_INIT;
- /* Mark slots as STACK_MISC if they belonged to spilled ptr/dynptr/iter. */
- if (is_stack_slot_special(&state->stack[spi]))
- for (i = 0; i < BPF_REG_SIZE; i++)
- scrub_spilled_slot(&state->stack[spi].slot_type[i]);
+ scrub_special_slot(state, spi);
/* when we zero initialize stack slots mark them as such */
if ((reg && register_is_null(reg)) ||
@@ -5467,8 +5474,13 @@ static int check_stack_write_var_off(struct bpf_verifier_env *env,
}
}
- /* Erase all other spilled pointers. */
- state->stack[spi].spilled_ptr.type = NOT_INIT;
+ /*
+ * Scrub slots if variable-offset stack write goes over spilled pointers.
+ * Otherwise is_spilled_reg() may == true && spilled_ptr.type == NOT_INIT
+ * and valid program is rejected by check_stack_read_fixed_off()
+ * with obscure "invalid size of register fill" message.
+ */
+ scrub_special_slot(state, spi);
/* Update the slot type. */
new_type = STACK_MISC;
@@ -5988,6 +6000,9 @@ static int map_kptr_match_type(struct bpf_verifier_env *env,
int perm_flags;
const char *reg_name = "";
+ if (base_type(reg->type) != PTR_TO_BTF_ID)
+ goto bad_type;
+
if (btf_is_kernel(reg->btf)) {
perm_flags = PTR_MAYBE_NULL | PTR_TRUSTED | MEM_RCU;
@@ -6000,7 +6015,7 @@ static int map_kptr_match_type(struct bpf_verifier_env *env,
perm_flags |= MEM_PERCPU;
}
- if (base_type(reg->type) != PTR_TO_BTF_ID || (type_flag(reg->type) & ~perm_flags))
+ if (type_flag(reg->type) & ~perm_flags)
goto bad_type;
/* We need to verify reg->type and reg->btf, before accessing reg->btf */
@@ -16210,11 +16225,20 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
int err;
dst_reg = ®s[insn->dst_reg];
- src_reg = NULL;
+ if (BPF_SRC(insn->code) == BPF_X)
+ src_reg = ®s[insn->src_reg];
+ else
+ src_reg = NULL;
- if (dst_reg->type == PTR_TO_ARENA) {
+ /* Case where at least one operand is an arena. */
+ if (dst_reg->type == PTR_TO_ARENA || (src_reg && src_reg->type == PTR_TO_ARENA)) {
struct bpf_insn_aux_data *aux = cur_aux(env);
+ if (dst_reg->type != PTR_TO_ARENA)
+ *dst_reg = *src_reg;
+
+ dst_reg->subreg_def = env->insn_idx + 1;
+
if (BPF_CLASS(insn->code) == BPF_ALU64)
/*
* 32-bit operations zero upper bits automatically.
@@ -16230,7 +16254,6 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
ptr_reg = dst_reg;
if (BPF_SRC(insn->code) == BPF_X) {
- src_reg = ®s[insn->src_reg];
if (src_reg->type != SCALAR_VALUE) {
if (dst_reg->type != SCALAR_VALUE) {
/* Combining two pointers by any ALU op yields
@@ -16313,7 +16336,8 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
*/
if (env->bpf_capable &&
(BPF_OP(insn->code) == BPF_ADD || BPF_OP(insn->code) == BPF_SUB) &&
- dst_reg->id && is_reg_const(src_reg, alu32)) {
+ dst_reg->id && is_reg_const(src_reg, alu32) &&
+ !(BPF_SRC(insn->code) == BPF_X && insn->src_reg == insn->dst_reg)) {
u64 val = reg_const_value(src_reg, alu32);
s32 off;
@@ -17930,6 +17954,23 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn)
mark_reg_unknown(env, regs, BPF_REG_0);
/* ld_abs load up to 32-bit skb data. */
regs[BPF_REG_0].subreg_def = env->insn_idx + 1;
+ /*
+ * See bpf_gen_ld_abs() which emits a hidden BPF_EXIT with r0=0
+ * which must be explored by the verifier when in a subprog.
+ */
+ if (env->cur_state->curframe) {
+ struct bpf_verifier_state *branch;
+
+ mark_reg_scratched(env, BPF_REG_0);
+ branch = push_stack(env, env->insn_idx + 1, env->insn_idx, false);
+ if (IS_ERR(branch))
+ return PTR_ERR(branch);
+ mark_reg_known_zero(env, regs, BPF_REG_0);
+ err = prepare_func_exit(env, &env->insn_idx);
+ if (err)
+ return err;
+ env->insn_idx--;
+ }
return 0;
}
@@ -18734,7 +18775,7 @@ static struct bpf_iarray *jt_from_subprog(struct bpf_verifier_env *env,
static struct bpf_iarray *
create_jt(int t, struct bpf_verifier_env *env)
{
- static struct bpf_subprog_info *subprog;
+ struct bpf_subprog_info *subprog;
int subprog_start, subprog_end;
struct bpf_iarray *jt;
int i;
@@ -18802,9 +18843,14 @@ static int visit_gotox_insn(int t, struct bpf_verifier_env *env)
return keep_exploring ? KEEP_EXPLORING : DONE_EXPLORING;
}
-static int visit_tailcall_insn(struct bpf_verifier_env *env, int t)
+/*
+ * Instructions that can abnormally return from a subprog (tail_call
+ * upon success, ld_{abs,ind} upon load failure) have a hidden exit
+ * that the verifier must account for.
+ */
+static int visit_abnormal_return_insn(struct bpf_verifier_env *env, int t)
{
- static struct bpf_subprog_info *subprog;
+ struct bpf_subprog_info *subprog;
struct bpf_iarray *jt;
if (env->insn_aux_data[t].jt)
@@ -18837,6 +18883,13 @@ static int visit_insn(int t, struct bpf_verifier_env *env)
/* All non-branch instructions have a single fall-through edge. */
if (BPF_CLASS(insn->code) != BPF_JMP &&
BPF_CLASS(insn->code) != BPF_JMP32) {
+ if (BPF_CLASS(insn->code) == BPF_LD &&
+ (BPF_MODE(insn->code) == BPF_ABS ||
+ BPF_MODE(insn->code) == BPF_IND)) {
+ ret = visit_abnormal_return_insn(env, t);
+ if (ret)
+ return ret;
+ }
insn_sz = bpf_is_ldimm64(insn) ? 2 : 1;
return push_insn(t, t + insn_sz, FALLTHROUGH, env);
}
@@ -18881,8 +18934,11 @@ static int visit_insn(int t, struct bpf_verifier_env *env)
mark_subprog_might_sleep(env, t);
if (bpf_helper_changes_pkt_data(insn->imm))
mark_subprog_changes_pkt_data(env, t);
- if (insn->imm == BPF_FUNC_tail_call)
- visit_tailcall_insn(env, t);
+ if (insn->imm == BPF_FUNC_tail_call) {
+ ret = visit_abnormal_return_insn(env, t);
+ if (ret)
+ return ret;
+ }
} else if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) {
struct bpf_kfunc_call_arg_meta meta;
@@ -19629,6 +19685,13 @@ static bool check_ids(u32 old_id, u32 cur_id, struct bpf_idmap *idmap)
* and r7.id=0 (both independent), without temp IDs both would map old_id=X
* to cur_id=0 and pass. With temp IDs: r6 maps X->temp1, r7 tries to map
* X->temp2, but X is already mapped to temp1, so the check fails correctly.
+ *
+ * When old_id has BPF_ADD_CONST set, the compound id (base | flag) and the
+ * base id (flag stripped) must both map consistently. Example: old has
+ * r2.id=A, r3.id=A|flag (r3 = r2 + delta), cur has r2.id=B, r3.id=C|flag
+ * (r3 derived from unrelated r4). Without the base check, idmap gets two
+ * independent entries A->B and A|flag->C|flag, missing that A->C conflicts
+ * with A->B. The base ID cross-check catches this.
*/
static bool check_scalar_ids(u32 old_id, u32 cur_id, struct bpf_idmap *idmap)
{
@@ -19637,7 +19700,15 @@ static bool check_scalar_ids(u32 old_id, u32 cur_id, struct bpf_idmap *idmap)
cur_id = cur_id ? cur_id : ++idmap->tmp_id_gen;
- return check_ids(old_id, cur_id, idmap);
+ if (!check_ids(old_id, cur_id, idmap))
+ return false;
+ if (old_id & BPF_ADD_CONST) {
+ old_id &= ~BPF_ADD_CONST;
+ cur_id &= ~BPF_ADD_CONST;
+ if (!check_ids(old_id, cur_id, idmap))
+ return false;
+ }
+ return true;
}
static void clean_func_state(struct bpf_verifier_env *env,
@@ -24897,7 +24968,7 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env)
}
for (i = 0; i < st_ops_desc->arg_info[member_idx].cnt; i++) {
- if (st_ops_desc->arg_info[member_idx].info->refcounted) {
+ if (st_ops_desc->arg_info[member_idx].info[i].refcounted) {
has_refcounted_arg = true;
break;
}
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 6b2ee75c63eb..8789ba613ea1 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -4018,33 +4018,41 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v)
static ssize_t pressure_write(struct kernfs_open_file *of, char *buf,
size_t nbytes, enum psi_res res)
{
- struct cgroup_file_ctx *ctx = of->priv;
+ struct cgroup_file_ctx *ctx;
struct psi_trigger *new;
struct cgroup *cgrp;
struct psi_group *psi;
+ ssize_t ret = 0;
cgrp = cgroup_kn_lock_live(of->kn, false);
if (!cgrp)
return -ENODEV;
- cgroup_get(cgrp);
- cgroup_kn_unlock(of->kn);
+ ctx = of->priv;
+ if (!ctx) {
+ ret = -ENODEV;
+ goto out_unlock;
+ }
/* Allow only one trigger per file descriptor */
if (ctx->psi.trigger) {
- cgroup_put(cgrp);
- return -EBUSY;
+ ret = -EBUSY;
+ goto out_unlock;
}
psi = cgroup_psi(cgrp);
new = psi_trigger_create(psi, buf, res, of->file, of);
if (IS_ERR(new)) {
- cgroup_put(cgrp);
- return PTR_ERR(new);
+ ret = PTR_ERR(new);
+ goto out_unlock;
}
smp_store_release(&ctx->psi.trigger, new);
- cgroup_put(cgrp);
+
+out_unlock:
+ cgroup_kn_unlock(of->kn);
+ if (ret)
+ return ret;
return nbytes;
}
diff --git a/kernel/cgroup/cpuset-internal.h b/kernel/cgroup/cpuset-internal.h
index fd7d19842ded..f7aaf01f7cd5 100644
--- a/kernel/cgroup/cpuset-internal.h
+++ b/kernel/cgroup/cpuset-internal.h
@@ -167,7 +167,13 @@ struct cpuset {
*/
int nr_deadline_tasks;
int nr_migrate_dl_tasks;
+ /* DL bandwidth that needs destination reservation for this attach. */
u64 sum_migrate_dl_bw;
+ /*
+ * CPU used for temporary DL bandwidth allocation during attach;
+ * -1 if no DL bandwidth was allocated in the current attach.
+ */
+ int dl_bw_cpu;
/* Invalid partition error code, not lock protected */
enum prs_errcode prs_err;
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 1335e437098e..cd79557e3f8e 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -288,6 +288,7 @@ struct cpuset top_cpuset = {
.flags = BIT(CS_CPU_EXCLUSIVE) |
BIT(CS_MEM_EXCLUSIVE) | BIT(CS_SCHED_LOAD_BALANCE),
.partition_root_state = PRS_ROOT,
+ .dl_bw_cpu = -1,
};
/**
@@ -579,6 +580,8 @@ static struct cpuset *dup_or_alloc_cpuset(struct cpuset *cs)
if (!trial)
return NULL;
+ trial->dl_bw_cpu = -1;
+
/* Setup cpumask pointer array */
cpumask_var_t *pmask[4] = {
&trial->cpus_allowed,
@@ -1715,7 +1718,8 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
*/
if (is_partition_valid(parent))
adding = cpumask_and(tmp->addmask,
- xcpus, parent->effective_xcpus);
+ cs->effective_xcpus,
+ parent->effective_xcpus);
if (old_prs > 0)
new_prs = -old_prs;
@@ -2980,6 +2984,7 @@ static void reset_migrate_dl_data(struct cpuset *cs)
{
cs->nr_migrate_dl_tasks = 0;
cs->sum_migrate_dl_bw = 0;
+ cs->dl_bw_cpu = -1;
}
/* Called by cgroups to determine if a cpuset is usable; cpuset_mutex held */
@@ -2989,7 +2994,7 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
struct cpuset *cs, *oldcs;
struct task_struct *task;
bool setsched_check;
- int ret;
+ int cpu, ret;
/* used later by cpuset_attach() */
cpuset_attach_old_cs = task_cs(cgroup_taskset_first(tset, &css));
@@ -3034,29 +3039,31 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
}
if (dl_task(task)) {
+ /*
+ * Count all migrating DL tasks for cpuset task accounting.
+ * Only tasks that need a root-domain bandwidth move
+ * contribute to sum_migrate_dl_bw.
+ */
cs->nr_migrate_dl_tasks++;
- cs->sum_migrate_dl_bw += task->dl.dl_bw;
+ if (dl_task_needs_bw_move(task, cs->effective_cpus))
+ cs->sum_migrate_dl_bw += task->dl.dl_bw;
}
}
- if (!cs->nr_migrate_dl_tasks)
+ if (!cs->sum_migrate_dl_bw)
goto out_success;
- if (!cpumask_intersects(oldcs->effective_cpus, cs->effective_cpus)) {
- int cpu = cpumask_any_and(cpu_active_mask, cs->effective_cpus);
+ cpu = cpumask_any_and(cpu_active_mask, cs->effective_cpus);
+ if (unlikely(cpu >= nr_cpu_ids)) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
- if (unlikely(cpu >= nr_cpu_ids)) {
- reset_migrate_dl_data(cs);
- ret = -EINVAL;
- goto out_unlock;
- }
+ ret = dl_bw_alloc(cpu, cs->sum_migrate_dl_bw);
+ if (ret)
+ goto out_unlock;
- ret = dl_bw_alloc(cpu, cs->sum_migrate_dl_bw);
- if (ret) {
- reset_migrate_dl_data(cs);
- goto out_unlock;
- }
- }
+ cs->dl_bw_cpu = cpu;
out_success:
/*
@@ -3064,7 +3071,10 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
* changes which zero cpus/mems_allowed.
*/
cs->attach_in_progress++;
+
out_unlock:
+ if (ret)
+ reset_migrate_dl_data(cs);
mutex_unlock(&cpuset_mutex);
return ret;
}
@@ -3080,12 +3090,11 @@ static void cpuset_cancel_attach(struct cgroup_taskset *tset)
mutex_lock(&cpuset_mutex);
dec_attach_in_progress_locked(cs);
- if (cs->nr_migrate_dl_tasks) {
- int cpu = cpumask_any(cs->effective_cpus);
+ if (cs->dl_bw_cpu >= 0)
+ dl_bw_free(cs->dl_bw_cpu, cs->sum_migrate_dl_bw);
- dl_bw_free(cpu, cs->sum_migrate_dl_bw);
+ if (cs->nr_migrate_dl_tasks)
reset_migrate_dl_data(cs);
- }
mutex_unlock(&cpuset_mutex);
}
diff --git a/kernel/cgroup/dmem.c b/kernel/cgroup/dmem.c
index 9d95824dc6fa..003cd8651de6 100644
--- a/kernel/cgroup/dmem.c
+++ b/kernel/cgroup/dmem.c
@@ -602,6 +602,7 @@ get_cg_pool_unlocked(struct dmemcg_state *cg, struct dmem_cgroup_region *region)
pool = NULL;
continue;
}
+ pool = ERR_PTR(-ENOMEM);
}
}
diff --git a/kernel/cgroup/rdma.c b/kernel/cgroup/rdma.c
index 09258eebb5c7..7d21a0db3cef 100644
--- a/kernel/cgroup/rdma.c
+++ b/kernel/cgroup/rdma.c
@@ -283,7 +283,7 @@ int rdmacg_try_charge(struct rdma_cgroup **rdmacg,
ret = PTR_ERR(rpool);
goto err;
} else {
- new = rpool->resources[index].usage + 1;
+ new = (s64)rpool->resources[index].usage + 1;
if (new > rpool->resources[index].max) {
ret = -EAGAIN;
goto err;
diff --git a/kernel/fork.c b/kernel/fork.c
index 2383c25b9fd4..73622ad0665a 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1949,9 +1949,11 @@ static void rv_task_fork(struct task_struct *p)
static bool need_futex_hash_allocate_default(u64 clone_flags)
{
- if ((clone_flags & (CLONE_THREAD | CLONE_VM)) != (CLONE_THREAD | CLONE_VM))
- return false;
- return true;
+ /*
+ * Allocate a default futex hash for any sibling that will
+ * share the parent's mm, except vfork.
+ */
+ return (clone_flags & (CLONE_VM | CLONE_VFORK)) == CLONE_VM;
}
/*
@@ -2338,10 +2340,6 @@ __latent_entropy struct task_struct *copy_process(
if (retval)
goto bad_fork_cancel_cgroup;
- /*
- * Allocate a default futex hash for the user process once the first
- * thread spawns.
- */
if (need_futex_hash_allocate_default(clone_flags)) {
retval = futex_hash_allocate_default();
if (retval)
@@ -3176,11 +3174,10 @@ int ksys_unshare(unsigned long unshare_flags)
new_cred, new_fs);
if (err)
goto bad_unshare_cleanup_cred;
-
if (new_cred) {
err = set_cred_ucounts(new_cred);
if (err)
- goto bad_unshare_cleanup_cred;
+ goto bad_unshare_cleanup_nsproxy;
}
if (new_fs || new_fd || do_sysvsem || new_cred || new_nsproxy) {
@@ -3196,8 +3193,10 @@ int ksys_unshare(unsigned long unshare_flags)
shm_init_task(current);
}
- if (new_nsproxy)
+ if (new_nsproxy) {
switch_task_namespaces(current, new_nsproxy);
+ new_nsproxy = NULL;
+ }
task_lock(current);
@@ -3226,13 +3225,15 @@ int ksys_unshare(unsigned long unshare_flags)
perf_event_namespaces(current);
+bad_unshare_cleanup_nsproxy:
+ if (new_nsproxy)
+ put_nsproxy(new_nsproxy);
bad_unshare_cleanup_cred:
if (new_cred)
put_cred(new_cred);
bad_unshare_cleanup_fd:
if (new_fd)
put_files_struct(new_fd);
-
bad_unshare_cleanup_fs:
if (new_fs)
free_fs_struct(new_fs);
diff --git a/kernel/futex/requeue.c b/kernel/futex/requeue.c
index d818b4d47f1b..b597cb3d17fc 100644
--- a/kernel/futex/requeue.c
+++ b/kernel/futex/requeue.c
@@ -319,8 +319,11 @@ futex_proxy_trylock_atomic(u32 __user *pifutex, struct futex_hash_bucket *hb1,
return -EINVAL;
/* Ensure that this does not race against an early wakeup */
- if (!futex_requeue_pi_prepare(top_waiter, NULL))
+ if (!futex_requeue_pi_prepare(top_waiter, NULL)) {
+ plist_del(&top_waiter->list, &hb1->chain);
+ futex_hb_waiters_dec(hb1);
return -EAGAIN;
+ }
/*
* Try to take the lock for top_waiter and set the FUTEX_WAITERS bit
@@ -722,10 +725,12 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
/*
* We were woken prior to requeue by a timeout or a signal.
- * Unqueue the futex_q and determine which it was.
+ * Conditionally unqueue the futex_q and determine which it was.
*/
- plist_del(&q->list, &hb->chain);
- futex_hb_waiters_dec(hb);
+ if (!plist_node_empty(&q->list)) {
+ plist_del(&q->list, &hb->chain);
+ futex_hb_waiters_dec(hb);
+ }
/* Handle spurious wakeups gracefully */
ret = -EWOULDBLOCK;
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
index 2a1d165b3167..c867f6c15530 100644
--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -171,7 +171,7 @@ static __always_inline bool __mutex_unlock_fast(struct mutex *lock)
#else /* !CONFIG_DEBUG_LOCK_ALLOC */
-void mutex_init_lockep(struct mutex *lock, const char *name, struct lock_class_key *key)
+void mutex_init_lockdep(struct mutex *lock, const char *name, struct lock_class_key *key)
{
__mutex_init_generic(lock);
@@ -181,7 +181,7 @@ void mutex_init_lockep(struct mutex *lock, const char *name, struct lock_class_k
debug_check_no_locks_freed((void *)lock, sizeof(*lock));
lockdep_init_map_wait(&lock->dep_map, name, key, 0, LD_WAIT_SLEEP);
}
-EXPORT_SYMBOL(mutex_init_lockep);
+EXPORT_SYMBOL(mutex_init_lockdep);
#endif /* !CONFIG_DEBUG_LOCK_ALLOC */
static inline void __mutex_set_flag(struct mutex *lock, unsigned long flag)
diff --git a/kernel/module/main.c b/kernel/module/main.c
index c3ce106c70af..ef2e2130972f 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -1408,7 +1408,7 @@ static void free_module(struct module *mod)
module_unload_free(mod);
/* Free any allocated parameters. */
- destroy_params(mod->kp, mod->num_kp);
+ module_destroy_params(mod->kp, mod->num_kp);
if (is_livepatch_module(mod))
free_module_elf(mod);
@@ -3519,7 +3519,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
mod_sysfs_teardown(mod);
coming_cleanup:
mod->state = MODULE_STATE_GOING;
- destroy_params(mod->kp, mod->num_kp);
+ module_destroy_params(mod->kp, mod->num_kp);
blocking_notifier_call_chain(&module_notify_list,
MODULE_STATE_GOING, mod);
klp_module_going(mod);
diff --git a/kernel/padata.c b/kernel/padata.c
index 8657e6e0c224..0d3ea1b68b1f 100644
--- a/kernel/padata.c
+++ b/kernel/padata.c
@@ -535,7 +535,8 @@ static void padata_init_reorder_list(struct parallel_data *pd)
}
/* Allocate and initialize the internal cpumask dependend resources. */
-static struct parallel_data *padata_alloc_pd(struct padata_shell *ps)
+static struct parallel_data *padata_alloc_pd(struct padata_shell *ps,
+ int offlining_cpu)
{
struct padata_instance *pinst = ps->pinst;
struct parallel_data *pd;
@@ -561,6 +562,10 @@ static struct parallel_data *padata_alloc_pd(struct padata_shell *ps)
cpumask_and(pd->cpumask.pcpu, pinst->cpumask.pcpu, cpu_online_mask);
cpumask_and(pd->cpumask.cbcpu, pinst->cpumask.cbcpu, cpu_online_mask);
+ if (offlining_cpu >= 0) {
+ __cpumask_clear_cpu(offlining_cpu, pd->cpumask.pcpu);
+ __cpumask_clear_cpu(offlining_cpu, pd->cpumask.cbcpu);
+ }
padata_init_reorder_list(pd);
padata_init_squeues(pd);
@@ -607,11 +612,11 @@ static void __padata_stop(struct padata_instance *pinst)
}
/* Replace the internal control structure with a new one. */
-static int padata_replace_one(struct padata_shell *ps)
+static int padata_replace_one(struct padata_shell *ps, int offlining_cpu)
{
struct parallel_data *pd_new;
- pd_new = padata_alloc_pd(ps);
+ pd_new = padata_alloc_pd(ps, offlining_cpu);
if (!pd_new)
return -ENOMEM;
@@ -621,7 +626,7 @@ static int padata_replace_one(struct padata_shell *ps)
return 0;
}
-static int padata_replace(struct padata_instance *pinst)
+static int padata_replace(struct padata_instance *pinst, int offlining_cpu)
{
struct padata_shell *ps;
int err = 0;
@@ -629,7 +634,7 @@ static int padata_replace(struct padata_instance *pinst)
pinst->flags |= PADATA_RESET;
list_for_each_entry(ps, &pinst->pslist, list) {
- err = padata_replace_one(ps);
+ err = padata_replace_one(ps, offlining_cpu);
if (err)
break;
}
@@ -646,9 +651,21 @@ static int padata_replace(struct padata_instance *pinst)
/* If cpumask contains no active cpu, we mark the instance as invalid. */
static bool padata_validate_cpumask(struct padata_instance *pinst,
- const struct cpumask *cpumask)
+ const struct cpumask *cpumask,
+ int offlining_cpu)
{
- if (!cpumask_intersects(cpumask, cpu_online_mask)) {
+ cpumask_copy(pinst->validate_cpumask, cpu_online_mask);
+
+ /*
+ * @offlining_cpu is still in cpu_online_mask, so remove it here for
+ * validation. Using a sub-CPUHP_TEARDOWN_CPU hotplug state where
+ * @offlining_cpu wouldn't be in the online mask doesn't work because
+ * padata_cpu_offline() can fail but such a state doesn't allow failure.
+ */
+ if (offlining_cpu >= 0)
+ __cpumask_clear_cpu(offlining_cpu, pinst->validate_cpumask);
+
+ if (!cpumask_intersects(cpumask, pinst->validate_cpumask)) {
pinst->flags |= PADATA_INVALID;
return false;
}
@@ -664,13 +681,13 @@ static int __padata_set_cpumasks(struct padata_instance *pinst,
int valid;
int err;
- valid = padata_validate_cpumask(pinst, pcpumask);
+ valid = padata_validate_cpumask(pinst, pcpumask, -1);
if (!valid) {
__padata_stop(pinst);
goto out_replace;
}
- valid = padata_validate_cpumask(pinst, cbcpumask);
+ valid = padata_validate_cpumask(pinst, cbcpumask, -1);
if (!valid)
__padata_stop(pinst);
@@ -678,7 +695,7 @@ static int __padata_set_cpumasks(struct padata_instance *pinst,
cpumask_copy(pinst->cpumask.pcpu, pcpumask);
cpumask_copy(pinst->cpumask.cbcpu, cbcpumask);
- err = padata_setup_cpumasks(pinst) ?: padata_replace(pinst);
+ err = padata_setup_cpumasks(pinst) ?: padata_replace(pinst, -1);
if (valid)
__padata_start(pinst);
@@ -730,36 +747,6 @@ EXPORT_SYMBOL(padata_set_cpumask);
#ifdef CONFIG_HOTPLUG_CPU
-static int __padata_add_cpu(struct padata_instance *pinst, int cpu)
-{
- int err = 0;
-
- if (cpumask_test_cpu(cpu, cpu_online_mask)) {
- err = padata_replace(pinst);
-
- if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) &&
- padata_validate_cpumask(pinst, pinst->cpumask.cbcpu))
- __padata_start(pinst);
- }
-
- return err;
-}
-
-static int __padata_remove_cpu(struct padata_instance *pinst, int cpu)
-{
- int err = 0;
-
- if (!cpumask_test_cpu(cpu, cpu_online_mask)) {
- if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) ||
- !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu))
- __padata_stop(pinst);
-
- err = padata_replace(pinst);
- }
-
- return err;
-}
-
static inline int pinst_has_cpu(struct padata_instance *pinst, int cpu)
{
return cpumask_test_cpu(cpu, pinst->cpumask.pcpu) ||
@@ -771,27 +758,39 @@ static int padata_cpu_online(unsigned int cpu, struct hlist_node *node)
struct padata_instance *pinst;
int ret;
- pinst = hlist_entry_safe(node, struct padata_instance, cpu_online_node);
+ pinst = hlist_entry_safe(node, struct padata_instance, cpuhp_node);
if (!pinst_has_cpu(pinst, cpu))
return 0;
mutex_lock(&pinst->lock);
- ret = __padata_add_cpu(pinst, cpu);
+
+ ret = padata_replace(pinst, -1);
+
+ if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu, -1) &&
+ padata_validate_cpumask(pinst, pinst->cpumask.cbcpu, -1))
+ __padata_start(pinst);
+
mutex_unlock(&pinst->lock);
return ret;
}
-static int padata_cpu_dead(unsigned int cpu, struct hlist_node *node)
+static int padata_cpu_offline(unsigned int cpu, struct hlist_node *node)
{
struct padata_instance *pinst;
int ret;
- pinst = hlist_entry_safe(node, struct padata_instance, cpu_dead_node);
+ pinst = hlist_entry_safe(node, struct padata_instance, cpuhp_node);
if (!pinst_has_cpu(pinst, cpu))
return 0;
mutex_lock(&pinst->lock);
- ret = __padata_remove_cpu(pinst, cpu);
+
+ if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu, cpu) ||
+ !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu, cpu))
+ __padata_stop(pinst);
+
+ ret = padata_replace(pinst, cpu);
+
mutex_unlock(&pinst->lock);
return ret;
}
@@ -802,15 +801,14 @@ static enum cpuhp_state hp_online;
static void __padata_free(struct padata_instance *pinst)
{
#ifdef CONFIG_HOTPLUG_CPU
- cpuhp_state_remove_instance_nocalls(CPUHP_PADATA_DEAD,
- &pinst->cpu_dead_node);
- cpuhp_state_remove_instance_nocalls(hp_online, &pinst->cpu_online_node);
+ cpuhp_state_remove_instance_nocalls(hp_online, &pinst->cpuhp_node);
#endif
WARN_ON(!list_empty(&pinst->pslist));
free_cpumask_var(pinst->cpumask.pcpu);
free_cpumask_var(pinst->cpumask.cbcpu);
+ free_cpumask_var(pinst->validate_cpumask);
destroy_workqueue(pinst->serial_wq);
destroy_workqueue(pinst->parallel_wq);
kfree(pinst);
@@ -971,10 +969,10 @@ struct padata_instance *padata_alloc(const char *name)
if (!alloc_cpumask_var(&pinst->cpumask.pcpu, GFP_KERNEL))
goto err_free_serial_wq;
- if (!alloc_cpumask_var(&pinst->cpumask.cbcpu, GFP_KERNEL)) {
- free_cpumask_var(pinst->cpumask.pcpu);
- goto err_free_serial_wq;
- }
+ if (!alloc_cpumask_var(&pinst->cpumask.cbcpu, GFP_KERNEL))
+ goto err_free_p_mask;
+ if (!alloc_cpumask_var(&pinst->validate_cpumask, GFP_KERNEL))
+ goto err_free_cb_mask;
INIT_LIST_HEAD(&pinst->pslist);
@@ -982,7 +980,7 @@ struct padata_instance *padata_alloc(const char *name)
cpumask_copy(pinst->cpumask.cbcpu, cpu_possible_mask);
if (padata_setup_cpumasks(pinst))
- goto err_free_masks;
+ goto err_free_v_mask;
__padata_start(pinst);
@@ -991,18 +989,19 @@ struct padata_instance *padata_alloc(const char *name)
#ifdef CONFIG_HOTPLUG_CPU
cpuhp_state_add_instance_nocalls_cpuslocked(hp_online,
- &pinst->cpu_online_node);
- cpuhp_state_add_instance_nocalls_cpuslocked(CPUHP_PADATA_DEAD,
- &pinst->cpu_dead_node);
+ &pinst->cpuhp_node);
#endif
cpus_read_unlock();
return pinst;
-err_free_masks:
- free_cpumask_var(pinst->cpumask.pcpu);
+err_free_v_mask:
+ free_cpumask_var(pinst->validate_cpumask);
+err_free_cb_mask:
free_cpumask_var(pinst->cpumask.cbcpu);
+err_free_p_mask:
+ free_cpumask_var(pinst->cpumask.pcpu);
err_free_serial_wq:
destroy_workqueue(pinst->serial_wq);
err_put_cpus:
@@ -1045,7 +1044,7 @@ struct padata_shell *padata_alloc_shell(struct padata_instance *pinst)
ps->pinst = pinst;
cpus_read_lock();
- pd = padata_alloc_pd(ps);
+ pd = padata_alloc_pd(ps, -1);
cpus_read_unlock();
if (!pd)
@@ -1094,31 +1093,24 @@ void __init padata_init(void)
int ret;
ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "padata:online",
- padata_cpu_online, NULL);
+ padata_cpu_online, padata_cpu_offline);
if (ret < 0)
goto err;
hp_online = ret;
-
- ret = cpuhp_setup_state_multi(CPUHP_PADATA_DEAD, "padata:dead",
- NULL, padata_cpu_dead);
- if (ret < 0)
- goto remove_online_state;
#endif
possible_cpus = num_possible_cpus();
padata_works = kmalloc_objs(struct padata_work, possible_cpus);
if (!padata_works)
- goto remove_dead_state;
+ goto remove_online_state;
for (i = 0; i < possible_cpus; ++i)
list_add(&padata_works[i].pw_list, &padata_free_works);
return;
-remove_dead_state:
-#ifdef CONFIG_HOTPLUG_CPU
- cpuhp_remove_multi_state(CPUHP_PADATA_DEAD);
remove_online_state:
+#ifdef CONFIG_HOTPLUG_CPU
cpuhp_remove_multi_state(hp_online);
err:
#endif
diff --git a/kernel/params.c b/kernel/params.c
index 7188a12dbe86..c6a354d54213 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -745,15 +745,6 @@ void module_param_sysfs_remove(struct module *mod)
}
#endif
-void destroy_params(const struct kernel_param *params, unsigned num)
-{
- unsigned int i;
-
- for (i = 0; i < num; i++)
- if (params[i].ops->free)
- params[i].ops->free(params[i].arg);
-}
-
struct module_kobject * __init_or_module
lookup_or_create_module_kobject(const char *name)
{
@@ -985,3 +976,21 @@ static int __init param_sysfs_builtin_init(void)
late_initcall(param_sysfs_builtin_init);
#endif /* CONFIG_SYSFS */
+
+#ifdef CONFIG_MODULES
+
+/*
+ * module_destroy_params - free all parameters for one module
+ * @params: module parameters (array)
+ * @num: number of module parameters
+ */
+void module_destroy_params(const struct kernel_param *params, unsigned int num)
+{
+ unsigned int i;
+
+ for (i = 0; i < num; i++)
+ if (params[i].ops->free)
+ params[i].ops->free(params[i].arg);
+}
+
+#endif /* CONFIG_MODULES */
diff --git a/kernel/printk/printk_ringbuffer.c b/kernel/printk/printk_ringbuffer.c
index 56c8e3d031f4..a3526bdd4e10 100644
--- a/kernel/printk/printk_ringbuffer.c
+++ b/kernel/printk/printk_ringbuffer.c
@@ -1302,10 +1302,6 @@ static const char *get_data(struct prb_data_ring *data_ring,
return NULL;
}
- /* Sanity check. Data-less blocks were handled earlier. */
- if (WARN_ON_ONCE(!data_check_size(data_ring, *data_size) || !*data_size))
- return NULL;
-
/* A valid data block will always be aligned to the ID size. */
if (WARN_ON_ONCE(blk_lpos->begin != ALIGN(blk_lpos->begin, sizeof(db->id))) ||
WARN_ON_ONCE(blk_lpos->next != ALIGN(blk_lpos->next, sizeof(db->id)))) {
@@ -1319,6 +1315,10 @@ static const char *get_data(struct prb_data_ring *data_ring,
/* Subtract block ID space from size to reflect data size. */
*data_size -= sizeof(db->id);
+ /* Sanity check the max size of the regular data block. */
+ if (WARN_ON_ONCE(!data_check_size(data_ring, *data_size)))
+ return NULL;
+
return &db->data[0];
}
diff --git a/kernel/rseq.c b/kernel/rseq.c
index 586f58f652c6..e75e3a5e312c 100644
--- a/kernel/rseq.c
+++ b/kernel/rseq.c
@@ -253,14 +253,16 @@ static bool rseq_handle_cs(struct task_struct *t, struct pt_regs *regs)
static void rseq_slowpath_update_usr(struct pt_regs *regs)
{
/*
- * Preserve rseq state and user_irq state. The generic entry code
- * clears user_irq on the way out, the non-generic entry
- * architectures are not having user_irq.
+ * Preserve has_rseq and user_irq state. The generic entry code clears
+ * user_irq on the way out, the non-generic entry architectures are not
+ * setting user_irq.
*/
- const struct rseq_event evt_mask = { .has_rseq = true, .user_irq = true, };
+ const struct rseq_event evt_mask = {
+ .has_rseq = RSEQ_HAS_RSEQ_VERSION_MASK,
+ .user_irq = true,
+ };
struct task_struct *t = current;
struct rseq_ids ids;
- u32 node_id;
bool event;
if (unlikely(t->flags & PF_EXITING))
@@ -296,9 +298,9 @@ static void rseq_slowpath_update_usr(struct pt_regs *regs)
if (!event)
return;
- node_id = cpu_to_node(ids.cpu_id);
+ ids.node_id = cpu_to_node(ids.cpu_id);
- if (unlikely(!rseq_update_usr(t, regs, &ids, node_id))) {
+ if (unlikely(!rseq_update_usr(t, regs, &ids))) {
/*
* Clear the errors just in case this might survive magically, but
* leave the rest intact.
@@ -330,8 +332,9 @@ void __rseq_handle_slowpath(struct pt_regs *regs)
void __rseq_signal_deliver(int sig, struct pt_regs *regs)
{
rseq_stat_inc(rseq_stats.signal);
+
/*
- * Don't update IDs, they are handled on exit to user if
+ * Don't update IDs yet, they are handled on exit to user if
* necessary. The important thing is to abort a critical section of
* the interrupted context as after this point the instruction
* pointer in @regs points to the signal handler.
@@ -344,6 +347,13 @@ void __rseq_signal_deliver(int sig, struct pt_regs *regs)
current->rseq.event.error = 0;
force_sigsegv(sig);
}
+
+ /*
+ * In legacy mode, force the update of IDs before returning to user
+ * space to stay compatible.
+ */
+ if (!rseq_v2(current))
+ rseq_force_update();
}
/*
@@ -402,66 +412,24 @@ static bool rseq_reset_ids(void)
/* The original rseq structure size (including padding) is 32 bytes. */
#define ORIG_RSEQ_SIZE 32
-/*
- * sys_rseq - setup restartable sequences for caller thread.
- */
-SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len, int, flags, u32, sig)
+static long rseq_register(struct rseq __user * rseq, u32 rseq_len, int flags, u32 sig)
{
u32 rseqfl = 0;
+ u8 version = 1;
- if (flags & RSEQ_FLAG_UNREGISTER) {
- if (flags & ~RSEQ_FLAG_UNREGISTER)
- return -EINVAL;
- /* Unregister rseq for current thread. */
- if (current->rseq.usrptr != rseq || !current->rseq.usrptr)
- return -EINVAL;
- if (rseq_len != current->rseq.len)
- return -EINVAL;
- if (current->rseq.sig != sig)
- return -EPERM;
- if (!rseq_reset_ids())
- return -EFAULT;
- rseq_reset(current);
- return 0;
- }
-
- if (unlikely(flags & ~(RSEQ_FLAG_SLICE_EXT_DEFAULT_ON)))
- return -EINVAL;
-
- if (current->rseq.usrptr) {
- /*
- * If rseq is already registered, check whether
- * the provided address differs from the prior
- * one.
- */
- if (current->rseq.usrptr != rseq || rseq_len != current->rseq.len)
- return -EINVAL;
- if (current->rseq.sig != sig)
- return -EPERM;
- /* Already registered. */
- return -EBUSY;
- }
+ if (!access_ok(rseq, rseq_len))
+ return -EFAULT;
/*
- * If there was no rseq previously registered, ensure the provided rseq
- * is properly aligned, as communcated to user-space through the ELF
- * auxiliary vector AT_RSEQ_ALIGN. If rseq_len is the original rseq
- * size, the required alignment is the original struct rseq alignment.
- *
- * The rseq_len is required to be greater or equal to the original rseq
- * size. In order to be valid, rseq_len is either the original rseq size,
- * or large enough to contain all supported fields, as communicated to
- * user-space through the ELF auxiliary vector AT_RSEQ_FEATURE_SIZE.
+ * Architectures, which use the generic IRQ entry code (at least) enable
+ * registrations with a size greater than the original v1 fixed sized
+ * @rseq_len, which has been validated already to utilize the optimized
+ * v2 ABI mode which also enables extended RSEQ features beyond MMCID.
*/
- if (rseq_len < ORIG_RSEQ_SIZE ||
- (rseq_len == ORIG_RSEQ_SIZE && !IS_ALIGNED((unsigned long)rseq, ORIG_RSEQ_SIZE)) ||
- (rseq_len != ORIG_RSEQ_SIZE && (!IS_ALIGNED((unsigned long)rseq, rseq_alloc_align()) ||
- rseq_len < offsetof(struct rseq, end))))
- return -EINVAL;
- if (!access_ok(rseq, rseq_len))
- return -EFAULT;
+ if (IS_ENABLED(CONFIG_GENERIC_IRQ_ENTRY) && rseq_len > ORIG_RSEQ_SIZE)
+ version = 2;
- if (IS_ENABLED(CONFIG_RSEQ_SLICE_EXTENSION)) {
+ if (IS_ENABLED(CONFIG_RSEQ_SLICE_EXTENSION) && version > 1) {
if (rseq_slice_extension_enabled()) {
rseqfl |= RSEQ_CS_FLAG_SLICE_EXT_AVAILABLE;
if (flags & RSEQ_FLAG_SLICE_EXT_DEFAULT_ON)
@@ -484,7 +452,15 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len, int, flags, u32
unsafe_put_user(RSEQ_CPU_ID_UNINITIALIZED, &rseq->cpu_id, efault);
unsafe_put_user(0U, &rseq->node_id, efault);
unsafe_put_user(0U, &rseq->mm_cid, efault);
- unsafe_put_user(0U, &rseq->slice_ctrl.all, efault);
+
+ /*
+ * All fields past mm_cid are only valid for non-legacy v2
+ * registrations.
+ */
+ if (version > 1) {
+ if (IS_ENABLED(CONFIG_RSEQ_SLICE_EXTENSION))
+ unsafe_put_user(0U, &rseq->slice_ctrl.all, efault);
+ }
}
/*
@@ -500,11 +476,10 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len, int, flags, u32
#endif
/*
- * If rseq was previously inactive, and has just been
- * registered, ensure the cpu_id_start and cpu_id fields
- * are updated before returning to user-space.
+ * Ensure the cpu_id_start and cpu_id fields are updated before
+ * returning to user-space.
*/
- current->rseq.event.has_rseq = true;
+ current->rseq.event.has_rseq = version;
rseq_force_update();
return 0;
@@ -512,6 +487,80 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len, int, flags, u32
return -EFAULT;
}
+static long rseq_unregister(struct rseq __user * rseq, u32 rseq_len, int flags, u32 sig)
+{
+ if (flags & ~RSEQ_FLAG_UNREGISTER)
+ return -EINVAL;
+ if (current->rseq.usrptr != rseq || !current->rseq.usrptr)
+ return -EINVAL;
+ if (rseq_len != current->rseq.len)
+ return -EINVAL;
+ if (current->rseq.sig != sig)
+ return -EPERM;
+ if (!rseq_reset_ids())
+ return -EFAULT;
+ rseq_reset(current);
+ return 0;
+}
+
+static long rseq_reregister(struct rseq __user * rseq, u32 rseq_len, u32 sig)
+{
+ /*
+ * If rseq is already registered, check whether the provided address
+ * differs from the prior one.
+ */
+ if (current->rseq.usrptr != rseq || rseq_len != current->rseq.len)
+ return -EINVAL;
+ if (current->rseq.sig != sig)
+ return -EPERM;
+ /* Already registered. */
+ return -EBUSY;
+}
+
+static bool rseq_length_valid(struct rseq __user *rseq, unsigned int rseq_len)
+{
+ /*
+ * Ensure the provided rseq is properly aligned, as communicated to
+ * user-space through the ELF auxiliary vector AT_RSEQ_ALIGN. If
+ * rseq_len is the original rseq size, the required alignment is the
+ * original struct rseq alignment.
+ *
+ * In order to be valid, rseq_len is either the original rseq size, or
+ * large enough to contain all supported fields, as communicated to
+ * user-space through the ELF auxiliary vector AT_RSEQ_FEATURE_SIZE.
+ */
+ if (rseq_len < ORIG_RSEQ_SIZE)
+ return false;
+
+ if (rseq_len == ORIG_RSEQ_SIZE)
+ return IS_ALIGNED((unsigned long)rseq, ORIG_RSEQ_SIZE);
+
+ return IS_ALIGNED((unsigned long)rseq, rseq_alloc_align()) &&
+ rseq_len >= offsetof(struct rseq, end);
+}
+
+#define RSEQ_FLAGS_SUPPORTED (RSEQ_FLAG_SLICE_EXT_DEFAULT_ON)
+
+/*
+ * sys_rseq - Register or unregister restartable sequences for the caller thread.
+ */
+SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len, int, flags, u32, sig)
+{
+ if (flags & RSEQ_FLAG_UNREGISTER)
+ return rseq_unregister(rseq, rseq_len, flags, sig);
+
+ if (unlikely(flags & ~RSEQ_FLAGS_SUPPORTED))
+ return -EINVAL;
+
+ if (current->rseq.usrptr)
+ return rseq_reregister(rseq, rseq_len, sig);
+
+ if (!rseq_length_valid(rseq, rseq_len))
+ return -EINVAL;
+
+ return rseq_register(rseq, rseq_len, flags, sig);
+}
+
#ifdef CONFIG_RSEQ_SLICE_EXTENSION
struct slice_timer {
struct hrtimer timer;
@@ -712,6 +761,8 @@ int rseq_slice_extension_prctl(unsigned long arg2, unsigned long arg3)
return -ENOTSUPP;
if (!current->rseq.usrptr)
return -ENXIO;
+ if (!rseq_v2(current))
+ return -ENOTSUPP;
/* No change? */
if (enable == !!current->rseq.slice.state.enabled)
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 14e947bcb3e5..567b1b1efdb5 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -4398,6 +4398,7 @@ static void __sched_fork(u64 clone_flags, struct task_struct *p)
p->se.nr_migrations = 0;
p->se.vruntime = 0;
p->se.vlag = 0;
+ p->se.rel_deadline = 0;
INIT_LIST_HEAD(&p->se.group_node);
/* A delayed task cannot be in clone(). */
@@ -6705,23 +6706,6 @@ find_proxy_task(struct rq *rq, struct task_struct *donor, struct rq_flags *rf)
}
#endif /* SCHED_PROXY_EXEC */
-static inline void proxy_tag_curr(struct rq *rq, struct task_struct *owner)
-{
- if (!sched_proxy_exec())
- return;
- /*
- * pick_next_task() calls set_next_task() on the chosen task
- * at some point, which ensures it is not push/pullable.
- * However, the chosen/donor task *and* the mutex owner form an
- * atomic pair wrt push/pull.
- *
- * Make sure owner we run is not pushable. Unfortunately we can
- * only deal with that by means of a dequeue/enqueue cycle. :-/
- */
- dequeue_task(rq, owner, DEQUEUE_NOCLOCK | DEQUEUE_SAVE);
- enqueue_task(rq, owner, ENQUEUE_NOCLOCK | ENQUEUE_RESTORE);
-}
-
/*
* __schedule() is the main scheduler function.
*
@@ -6874,9 +6858,6 @@ static void __sched notrace __schedule(int sched_mode)
*/
RCU_INIT_POINTER(rq->curr, next);
- if (!task_current_donor(rq, next))
- proxy_tag_curr(rq, next);
-
/*
* The membarrier system call requires each architecture
* to have a full memory barrier after updating
@@ -6910,10 +6891,6 @@ static void __sched notrace __schedule(int sched_mode)
/* Also unlocks the rq: */
rq = context_switch(rq, prev, next, &rf);
} else {
- /* In case next was already curr but just got blocked_donor */
- if (!task_current_donor(rq, next))
- proxy_tag_curr(rq, next);
-
rq_unpin_lock(rq, &rf);
__balance_callbacks(rq, NULL);
raw_spin_rq_unlock_irq(rq);
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index 153232dd8276..ae9fd211cec1 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -461,6 +461,7 @@ static void sugov_update_single_perf(struct update_util_data *hook, u64 time,
unsigned int flags)
{
struct sugov_cpu *sg_cpu = container_of(hook, struct sugov_cpu, update_util);
+ struct sugov_policy *sg_policy = sg_cpu->sg_policy;
unsigned long prev_util = sg_cpu->util;
unsigned long max_cap;
@@ -482,10 +483,10 @@ static void sugov_update_single_perf(struct update_util_data *hook, u64 time,
if (sugov_hold_freq(sg_cpu) && sg_cpu->util < prev_util)
sg_cpu->util = prev_util;
- cpufreq_driver_adjust_perf(sg_cpu->cpu, sg_cpu->bw_min,
+ cpufreq_driver_adjust_perf(sg_policy->policy, sg_cpu->bw_min,
sg_cpu->util, max_cap);
- sg_cpu->sg_policy->last_freq_update_time = time;
+ sg_policy->last_freq_update_time = time;
}
static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu, u64 time)
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index 674de6a48551..af7c1e88e46e 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -2801,12 +2801,26 @@ static int find_later_rq(struct task_struct *task)
static struct task_struct *pick_next_pushable_dl_task(struct rq *rq)
{
- struct task_struct *p;
+ struct task_struct *i, *p = NULL;
+ struct rb_node *next_node;
if (!has_pushable_dl_tasks(rq))
return NULL;
- p = __node_2_pdl(rb_first_cached(&rq->dl.pushable_dl_tasks_root));
+ next_node = rb_first_cached(&rq->dl.pushable_dl_tasks_root);
+ while (next_node) {
+ i = __node_2_pdl(next_node);
+ /* make sure task isn't on_cpu (possible with proxy-exec) */
+ if (!task_on_cpu(rq, i)) {
+ p = i;
+ break;
+ }
+
+ next_node = rb_next(next_node);
+ }
+
+ if (!p)
+ return NULL;
WARN_ON_ONCE(rq->cpu != task_cpu(p));
WARN_ON_ONCE(task_current(rq, p));
@@ -3092,20 +3106,18 @@ static void task_woken_dl(struct rq *rq, struct task_struct *p)
static void set_cpus_allowed_dl(struct task_struct *p,
struct affinity_context *ctx)
{
- struct root_domain *src_rd;
struct rq *rq;
WARN_ON_ONCE(!dl_task(p));
rq = task_rq(p);
- src_rd = rq->rd;
/*
* Migrating a SCHED_DEADLINE task between exclusive
* cpusets (different root_domains) entails a bandwidth
* update. We already made space for us in the destination
* domain (see cpuset_can_attach()).
*/
- if (!cpumask_intersects(src_rd->span, ctx->new_mask)) {
+ if (dl_task_needs_bw_move(p, ctx->new_mask)) {
struct dl_bw *src_dl_b;
src_dl_b = dl_bw_of(cpu_of(rq));
@@ -3122,6 +3134,15 @@ static void set_cpus_allowed_dl(struct task_struct *p,
set_cpus_allowed_common(p, ctx);
}
+bool dl_task_needs_bw_move(struct task_struct *p,
+ const struct cpumask *new_mask)
+{
+ if (!dl_task(p))
+ return false;
+
+ return !cpumask_intersects(task_rq(p)->rd->span, new_mask);
+}
+
/* Assumes rq->lock is held */
static void rq_online_dl(struct rq *rq)
{
diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 9c7ff5179e4f..3ac01ea9bfb1 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -2742,7 +2742,7 @@ static void set_cpus_allowed_scx(struct task_struct *p,
* designation pointless. Cast it away when calling the operation.
*/
if (SCX_HAS_OP(sch, set_cpumask))
- SCX_CALL_OP_TASK(sch, SCX_KF_REST, set_cpumask, NULL,
+ SCX_CALL_OP_TASK(sch, SCX_KF_REST, set_cpumask, task_rq(p),
p, (struct cpumask *)p->cpus_ptr);
}
@@ -3406,7 +3406,7 @@ void scx_cgroup_move_task(struct task_struct *p)
*/
if (SCX_HAS_OP(sch, cgroup_move) &&
!WARN_ON_ONCE(!p->scx.cgrp_moving_from))
- SCX_CALL_OP_TASK(sch, SCX_KF_UNLOCKED, cgroup_move, NULL,
+ SCX_CALL_OP_TASK(sch, SCX_KF_REST, cgroup_move, task_rq(p),
p, p->scx.cgrp_moving_from,
tg_cgrp(task_group(p)));
p->scx.cgrp_moving_from = NULL;
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index ab4114712be7..3bce48ad0bc5 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -1007,7 +1007,7 @@ static inline void cancel_protect_slice(struct sched_entity *se)
*
* Which allows tree pruning through eligibility.
*/
-static struct sched_entity *__pick_eevdf(struct cfs_rq *cfs_rq, bool protect)
+static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq, bool protect)
{
struct rb_node *node = cfs_rq->tasks_timeline.rb_root.rb_node;
struct sched_entity *se = __pick_first_entity(cfs_rq);
@@ -1078,11 +1078,6 @@ static struct sched_entity *__pick_eevdf(struct cfs_rq *cfs_rq, bool protect)
return best;
}
-static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq)
-{
- return __pick_eevdf(cfs_rq, true);
-}
-
struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq)
{
struct rb_node *last = rb_last(&cfs_rq->tasks_timeline.rb_root);
@@ -5540,11 +5535,11 @@ static int dequeue_entities(struct rq *rq, struct sched_entity *se, int flags);
* 4) do not run the "skip" process, if something else is available
*/
static struct sched_entity *
-pick_next_entity(struct rq *rq, struct cfs_rq *cfs_rq)
+pick_next_entity(struct rq *rq, struct cfs_rq *cfs_rq, bool protect)
{
struct sched_entity *se;
- se = pick_eevdf(cfs_rq);
+ se = pick_eevdf(cfs_rq, protect);
if (se->sched_delayed) {
dequeue_entities(rq, se, DEQUEUE_SLEEP | DEQUEUE_DELAYED);
/*
@@ -8809,7 +8804,7 @@ static void wakeup_preempt_fair(struct rq *rq, struct task_struct *p, int wake_f
{
enum preempt_wakeup_action preempt_action = PREEMPT_WAKEUP_PICK;
struct task_struct *donor = rq->donor;
- struct sched_entity *se = &donor->se, *pse = &p->se;
+ struct sched_entity *nse, *se = &donor->se, *pse = &p->se;
struct cfs_rq *cfs_rq = task_cfs_rq(donor);
int cse_is_idle, pse_is_idle;
@@ -8920,11 +8915,18 @@ static void wakeup_preempt_fair(struct rq *rq, struct task_struct *p, int wake_f
}
pick:
+ nse = pick_next_entity(rq, cfs_rq, preempt_action != PREEMPT_WAKEUP_SHORT);
+ /* If @p has become the most eligible task, force preemption */
+ if (nse == pse)
+ goto preempt;
+
/*
- * If @p has become the most eligible task, force preemption.
+ * Because p is enqueued, nse being null can only mean that we
+ * dequeued a delayed task. If there are still entities queued in
+ * cfs, check if the next one will be p.
*/
- if (__pick_eevdf(cfs_rq, preempt_action != PREEMPT_WAKEUP_SHORT) == pse)
- goto preempt;
+ if (!nse && cfs_rq->nr_queued)
+ goto pick;
if (sched_feat(RUN_TO_PARITY))
update_protect_slice(cfs_rq, se);
@@ -8959,7 +8961,7 @@ static struct task_struct *pick_task_fair(struct rq *rq, struct rq_flags *rf)
throttled |= check_cfs_rq_runtime(cfs_rq);
- se = pick_next_entity(rq, cfs_rq);
+ se = pick_next_entity(rq, cfs_rq, true);
if (!se)
goto again;
cfs_rq = group_cfs_rq(se);
diff --git a/kernel/sched/membarrier.c b/kernel/sched/membarrier.c
index 623445603725..226a6329f3e9 100644
--- a/kernel/sched/membarrier.c
+++ b/kernel/sched/membarrier.c
@@ -199,7 +199,16 @@ static void ipi_rseq(void *info)
* is negligible.
*/
smp_mb();
- rseq_sched_switch_event(current);
+ /*
+ * Legacy mode requires that IDs are written and the critical section is
+ * evaluated. V2 optimized mode handles the critical section and IDs are
+ * only updated if they change as a consequence of preemption after
+ * return from this IPI.
+ */
+ if (rseq_v2(current))
+ rseq_sched_switch_event(current);
+ else
+ rseq_force_update();
}
static void ipi_sync_rq_state(void *info)
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 906f6c656c2e..0cbee031858a 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1853,13 +1853,22 @@ static int find_lowest_rq(struct task_struct *task)
static struct task_struct *pick_next_pushable_task(struct rq *rq)
{
- struct task_struct *p;
+ struct plist_head *head = &rq->rt.pushable_tasks;
+ struct task_struct *i, *p = NULL;
if (!has_pushable_tasks(rq))
return NULL;
- p = plist_first_entry(&rq->rt.pushable_tasks,
- struct task_struct, pushable_tasks);
+ plist_for_each_entry(i, head, pushable_tasks) {
+ /* make sure task isn't on_cpu (possible with proxy-exec) */
+ if (!task_on_cpu(rq, i)) {
+ p = i;
+ break;
+ }
+ }
+
+ if (!p)
+ return NULL;
BUG_ON(rq->cpu != task_cpu(p));
BUG_ON(task_current(rq, p));
@@ -2676,9 +2685,6 @@ static int tg_rt_schedulable(struct task_group *tg, void *data)
tg->rt_bandwidth.rt_runtime && tg_has_rt_tasks(tg))
return -EBUSY;
- if (WARN_ON(!rt_group_sched_enabled() && tg != &root_task_group))
- return -EBUSY;
-
total = to_ratio(period, runtime);
/*
@@ -2822,6 +2828,8 @@ long sched_group_rt_period(struct task_group *tg)
static int sched_rt_global_constraints(void)
{
int ret = 0;
+ if (!rt_group_sched_enabled())
+ return ret;
mutex_lock(&rt_constraints_mutex);
ret = __rt_schedulable(NULL, 0, 0);
diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c
index 32dcddaead82..2864f43bff6d 100644
--- a/kernel/sched/topology.c
+++ b/kernel/sched/topology.c
@@ -1643,13 +1643,17 @@ sd_init(struct sched_domain_topology_level *tl,
int sd_id, sd_weight, sd_flags = 0;
struct cpumask *sd_span;
- sd_weight = cpumask_weight(tl->mask(tl, cpu));
+ sd_span = sched_domain_span(sd);
+ cpumask_and(sd_span, cpu_map, tl->mask(tl, cpu));
+ sd_weight = cpumask_weight(sd_span);
+ sd_id = cpumask_first(sd_span);
if (tl->sd_flags)
sd_flags = (*tl->sd_flags)();
if (WARN_ONCE(sd_flags & ~TOPOLOGY_SD_FLAGS,
- "wrong sd_flags in topology description\n"))
+ "wrong sd_flags in topology description\n"))
sd_flags &= TOPOLOGY_SD_FLAGS;
+ sd_flags |= asym_cpu_capacity_classify(sd_span, cpu_map);
*sd = (struct sched_domain){
.min_interval = sd_weight,
@@ -1686,12 +1690,6 @@ sd_init(struct sched_domain_topology_level *tl,
.name = tl->name,
};
- sd_span = sched_domain_span(sd);
- cpumask_and(sd_span, cpu_map, tl->mask(tl, cpu));
- sd_id = cpumask_first(sd_span);
-
- sd->flags |= asym_cpu_capacity_classify(sd_span, cpu_map);
-
WARN_ONCE((sd->flags & (SD_SHARE_CPUCAPACITY | SD_ASYM_CPUCAPACITY)) ==
(SD_SHARE_CPUCAPACITY | SD_ASYM_CPUCAPACITY),
"CPU capacity asymmetry not supported on SMT\n");
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 1e37142fe52f..c450b41d4bb5 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -479,17 +479,10 @@ static inline void debug_setup_on_stack(struct hrtimer *timer, clockid_t clockid
trace_hrtimer_setup(timer, clockid, mode);
}
-static inline void debug_activate(struct hrtimer *timer,
- enum hrtimer_mode mode)
+static inline void debug_activate(struct hrtimer *timer, enum hrtimer_mode mode, bool was_armed)
{
debug_hrtimer_activate(timer, mode);
- trace_hrtimer_start(timer, mode);
-}
-
-static inline void debug_deactivate(struct hrtimer *timer)
-{
- debug_hrtimer_deactivate(timer);
- trace_hrtimer_cancel(timer);
+ trace_hrtimer_start(timer, mode, was_armed);
}
static struct hrtimer_clock_base *
@@ -1084,9 +1077,9 @@ EXPORT_SYMBOL_GPL(hrtimer_forward);
* Returns true when the new timer is the leftmost timer in the tree.
*/
static bool enqueue_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base,
- enum hrtimer_mode mode)
+ enum hrtimer_mode mode, bool was_armed)
{
- debug_activate(timer, mode);
+ debug_activate(timer, mode, was_armed);
WARN_ON_ONCE(!base->cpu_base->online);
base->cpu_base->active_bases |= 1 << base->index;
@@ -1146,6 +1139,8 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base,
if (state & HRTIMER_STATE_ENQUEUED) {
bool reprogram;
+ debug_hrtimer_deactivate(timer);
+
/*
* Remove the timer and force reprogramming when high
* resolution mode is active and the timer is on the current
@@ -1154,7 +1149,6 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base,
* reprogramming happens in the interrupt handler. This is a
* rare case and less expensive than a smp call.
*/
- debug_deactivate(timer);
reprogram = base->cpu_base == this_cpu_ptr(&hrtimer_bases);
/*
@@ -1221,15 +1215,15 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
{
struct hrtimer_cpu_base *this_cpu_base = this_cpu_ptr(&hrtimer_bases);
struct hrtimer_clock_base *new_base;
- bool force_local, first;
+ bool force_local, first, was_armed;
/*
* If the timer is on the local cpu base and is the first expiring
* timer then this might end up reprogramming the hardware twice
- * (on removal and on enqueue). To avoid that by prevent the
- * reprogram on removal, keep the timer local to the current CPU
- * and enforce reprogramming after it is queued no matter whether
- * it is the new first expiring timer again or not.
+ * (on removal and on enqueue). To avoid that prevent the reprogram
+ * on removal, keep the timer local to the current CPU and enforce
+ * reprogramming after it is queued no matter whether it is the new
+ * first expiring timer again or not.
*/
force_local = base->cpu_base == this_cpu_base;
force_local &= base->cpu_base->next_timer == timer;
@@ -1251,7 +1245,7 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
* avoids programming the underlying clock event twice (once at
* removal and once after enqueue).
*/
- remove_hrtimer(timer, base, true, force_local);
+ was_armed = remove_hrtimer(timer, base, true, force_local);
if (mode & HRTIMER_MODE_REL)
tim = ktime_add_safe(tim, __hrtimer_cb_get_time(base->clockid));
@@ -1268,7 +1262,15 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
new_base = base;
}
- first = enqueue_hrtimer(timer, new_base, mode);
+ first = enqueue_hrtimer(timer, new_base, mode, was_armed);
+
+ /*
+ * If the hrtimer interrupt is running, then it will reevaluate the
+ * clock bases and reprogram the clock event device.
+ */
+ if (new_base->cpu_base->in_hrtirq)
+ return false;
+
if (!force_local) {
/*
* If the current CPU base is online, then the timer is
@@ -1362,8 +1364,11 @@ int hrtimer_try_to_cancel(struct hrtimer *timer)
base = lock_hrtimer_base(timer, &flags);
- if (!hrtimer_callback_running(timer))
+ if (!hrtimer_callback_running(timer)) {
ret = remove_hrtimer(timer, base, false, false);
+ if (ret)
+ trace_hrtimer_cancel(timer);
+ }
unlock_hrtimer_base(timer, &flags);
@@ -1799,7 +1804,7 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base,
*/
if (restart != HRTIMER_NORESTART &&
!(timer->state & HRTIMER_STATE_ENQUEUED))
- enqueue_hrtimer(timer, base, HRTIMER_MODE_ABS);
+ enqueue_hrtimer(timer, base, HRTIMER_MODE_ABS, false);
/*
* Separate the ->running assignment from the ->state assignment.
@@ -2279,7 +2284,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
while ((node = timerqueue_getnext(&old_base->active))) {
timer = container_of(node, struct hrtimer, node);
BUG_ON(hrtimer_callback_running(timer));
- debug_deactivate(timer);
+ debug_hrtimer_deactivate(timer);
/*
* Mark it as ENQUEUED not INACTIVE otherwise the
@@ -2296,7 +2301,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
* sort out already expired timers and reprogram the
* event device.
*/
- enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS);
+ enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS, true);
}
}
diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c
index 6809b370e991..d1564db95a8f 100644
--- a/kernel/trace/trace_branch.c
+++ b/kernel/trace/trace_branch.c
@@ -373,10 +373,10 @@ __init static int init_annotated_branch_stats(void)
int ret;
ret = register_stat_tracer(&annotated_branch_stats);
- if (!ret) {
+ if (ret) {
printk(KERN_WARNING "Warning: could not register "
"annotated branches stats\n");
- return 1;
+ return ret;
}
return 0;
}
@@ -438,10 +438,10 @@ __init static int all_annotated_branch_stats(void)
int ret;
ret = register_stat_tracer(&all_branch_stats);
- if (!ret) {
+ if (ret) {
printk(KERN_WARNING "Warning: could not register "
"all branches stats\n");
- return 1;
+ return ret;
}
return 0;
}
diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index 73ea180cad55..f9c8a4f078ea 100644
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -1361,12 +1361,14 @@ static const char *hist_field_name(struct hist_field *field,
field->flags & HIST_FIELD_FL_VAR_REF) {
if (field->system) {
static char full_name[MAX_FILTER_STR_VAL];
+ int len;
+
+ len = snprintf(full_name, sizeof(full_name), "%s.%s.%s",
+ field->system, field->event_name,
+ field->name);
+ if (len >= sizeof(full_name))
+ return NULL;
- strcat(full_name, field->system);
- strcat(full_name, ".");
- strcat(full_name, field->event_name);
- strcat(full_name, ".");
- strcat(full_name, field->name);
field_name = full_name;
} else
field_name = field->name;
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index a5dbb72528e0..058724c41c46 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -765,6 +765,14 @@ static unsigned int number_of_same_symbols(const char *mod, const char *func_nam
if (!mod)
kallsyms_on_each_match_symbol(count_symbols, func_name, &ctx.count);
+ /*
+ * If the symbol is found in vmlinux, use vmlinux resolution only.
+ * This prevents module symbols from shadowing vmlinux symbols
+ * and causing -EADDRNOTAVAIL for unqualified kprobe targets.
+ */
+ if (!mod && ctx.count > 0)
+ return ctx.count;
+
module_kallsyms_on_each_symbol(mod, count_mod_symbols, &ctx);
return ctx.count;
diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c
index 5ea5e0d76f00..3ea17af60169 100644
--- a/kernel/trace/trace_printk.c
+++ b/kernel/trace/trace_printk.c
@@ -197,6 +197,7 @@ struct notifier_block module_trace_bprintk_format_nb = {
.notifier_call = module_trace_bprintk_format_notify,
};
+__printf(2, 3)
int __trace_bprintk(unsigned long ip, const char *fmt, ...)
{
int ret;
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index c6ea96d5b716..23053ef54162 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -41,6 +41,7 @@
#include <linux/mempolicy.h>
#include <linux/freezer.h>
#include <linux/debug_locks.h>
+#include <linux/device/devres.h>
#include <linux/lockdep.h>
#include <linux/idr.h>
#include <linux/jhash.h>
@@ -5628,7 +5629,9 @@ static int alloc_and_link_pwqs(struct workqueue_struct *wq)
ret = apply_workqueue_attrs_locked(wq, unbound_std_wq_attrs[highpri]);
}
- return ret;
+ if (ret)
+ goto enomem;
+ return 0;
enomem:
if (wq->cpu_pwq) {
@@ -5884,6 +5887,21 @@ static struct workqueue_struct *__alloc_workqueue(const char *fmt,
return NULL;
}
+__printf(1, 0)
+static struct workqueue_struct *alloc_workqueue_va(const char *fmt,
+ unsigned int flags,
+ int max_active,
+ va_list args)
+{
+ struct workqueue_struct *wq;
+
+ wq = __alloc_workqueue(fmt, flags, max_active, args);
+ if (wq)
+ wq_init_lockdep(wq);
+
+ return wq;
+}
+
__printf(1, 4)
struct workqueue_struct *alloc_workqueue_noprof(const char *fmt,
unsigned int flags,
@@ -5893,16 +5911,39 @@ struct workqueue_struct *alloc_workqueue_noprof(const char *fmt,
va_list args;
va_start(args, max_active);
- wq = __alloc_workqueue(fmt, flags, max_active, args);
+ wq = alloc_workqueue_va(fmt, flags, max_active, args);
+ va_end(args);
+
+ return wq;
+}
+EXPORT_SYMBOL_GPL(alloc_workqueue_noprof);
+
+static void devm_workqueue_release(void *res)
+{
+ destroy_workqueue(res);
+}
+
+__printf(2, 5) struct workqueue_struct *
+devm_alloc_workqueue_noprof(struct device *dev, const char *fmt,
+ unsigned int flags, int max_active, ...)
+{
+ struct workqueue_struct *wq;
+ va_list args;
+ int ret;
+
+ va_start(args, max_active);
+ wq = alloc_workqueue_va(fmt, flags, max_active, args);
va_end(args);
if (!wq)
return NULL;
- wq_init_lockdep(wq);
+ ret = devm_add_action_or_reset(dev, devm_workqueue_release, wq);
+ if (ret)
+ return NULL;
return wq;
}
-EXPORT_SYMBOL_GPL(alloc_workqueue_noprof);
+EXPORT_SYMBOL_GPL(devm_alloc_workqueue_noprof);
#ifdef CONFIG_LOCKDEP
__printf(1, 5)
diff --git a/lib/tests/kunit_iov_iter.c b/lib/tests/kunit_iov_iter.c
index bb847e5010eb..d16449bdb833 100644
--- a/lib/tests/kunit_iov_iter.c
+++ b/lib/tests/kunit_iov_iter.c
@@ -42,7 +42,7 @@ static inline u8 pattern(unsigned long x)
static void iov_kunit_unmap(void *data)
{
- vunmap(data);
+ vfree(data);
}
static void *__init iov_kunit_create_buffer(struct kunit *test,
@@ -53,17 +53,22 @@ static void *__init iov_kunit_create_buffer(struct kunit *test,
unsigned long got;
void *buffer;
- pages = kunit_kcalloc(test, npages, sizeof(struct page *), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pages);
+ pages = kzalloc_objs(struct page *, npages, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pages);
*ppages = pages;
got = alloc_pages_bulk(GFP_KERNEL, npages, pages);
if (got != npages) {
release_pages(pages, got);
+ kvfree(pages);
KUNIT_ASSERT_EQ(test, got, npages);
}
buffer = vmap(pages, npages, VM_MAP | VM_MAP_PUT_PAGES, PAGE_KERNEL);
+ if (buffer == NULL) {
+ release_pages(pages, got);
+ kvfree(pages);
+ }
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buffer);
kunit_add_action_or_reset(test, iov_kunit_unmap, buffer);
@@ -369,9 +374,6 @@ static void iov_kunit_destroy_folioq(void *data)
for (folioq = data; folioq; folioq = next) {
next = folioq->next;
- for (int i = 0; i < folioq_nr_slots(folioq); i++)
- if (folioq_folio(folioq, i))
- folio_put(folioq_folio(folioq, i));
kfree(folioq);
}
}
diff --git a/mm/Kconfig b/mm/Kconfig
index ebd8ea353687..befa8909ae29 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -572,6 +572,7 @@ config SPLIT_PTE_PTLOCKS
depends on !ARM || CPU_CACHE_VIPT
depends on !PARISC || PA20
depends on !SPARC32
+ depends on !UML
config ARCH_ENABLE_SPLIT_PMD_PTLOCK
bool
diff --git a/mm/memblock.c b/mm/memblock.c
index b3ddfdec7a80..d4a02f1750e9 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -2434,7 +2434,7 @@ int reserve_mem_release_by_name(const char *name)
return 0;
start = phys_to_virt(map->start);
- end = start + map->size - 1;
+ end = start + map->size;
snprintf(buf, sizeof(buf), "reserve_mem:%s", name);
free_reserved_area(start, end, 0, buf);
map->size = 0;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 0df1c0cbc8f7..1b3b9131affa 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3340,8 +3340,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data,
memcpy(conn->dev_class, ev->dev_class, 3);
- hci_dev_unlock(hdev);
-
if (ev->link_type == ACL_LINK ||
(!(flags & HCI_PROTO_DEFER) && !lmp_esco_capable(hdev))) {
struct hci_cp_accept_conn_req cp;
@@ -3375,7 +3373,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data,
hci_connect_cfm(conn, 0);
}
- return;
unlock:
hci_dev_unlock(hdev);
}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 95c65fece39b..0d8053a3fc0a 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -5473,7 +5473,13 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
if (chan->ident != cmd->ident)
continue;
+ l2cap_chan_hold(chan);
+ l2cap_chan_lock(chan);
+
l2cap_chan_del(chan, ECONNRESET);
+
+ l2cap_chan_unlock(chan);
+ l2cap_chan_put(chan);
}
return 0;
@@ -6733,7 +6739,7 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
if (sdu_len > chan->imtu) {
BT_ERR("Too big LE L2CAP SDU length: len %u > %u",
- skb->len, sdu_len);
+ sdu_len, chan->imtu);
l2cap_send_disconn_req(chan, ECONNRESET);
err = -EMSGSIZE;
goto failed;
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index b84587811ef4..18826d4b9c0b 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -1045,7 +1045,8 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
codecs = (void *)buffer;
- if (codecs->num_codecs > 1) {
+ if (codecs->num_codecs != 1 ||
+ optlen < struct_size(codecs, codecs, codecs->num_codecs)) {
hci_dev_put(hdev);
err = -EINVAL;
break;
diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c
index 178c4738e63b..2988175a47f2 100644
--- a/net/bpf/test_run.c
+++ b/net/bpf/test_run.c
@@ -1120,19 +1120,23 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,
switch (skb->protocol) {
case htons(ETH_P_IP):
- sk->sk_family = AF_INET;
- if (sizeof(struct iphdr) <= skb_headlen(skb)) {
- sk->sk_rcv_saddr = ip_hdr(skb)->saddr;
- sk->sk_daddr = ip_hdr(skb)->daddr;
+ if (skb_headlen(skb) < sizeof(struct iphdr)) {
+ ret = -EINVAL;
+ goto out;
}
+ sk->sk_family = AF_INET;
+ sk->sk_rcv_saddr = ip_hdr(skb)->saddr;
+ sk->sk_daddr = ip_hdr(skb)->daddr;
break;
#if IS_ENABLED(CONFIG_IPV6)
case htons(ETH_P_IPV6):
- sk->sk_family = AF_INET6;
- if (sizeof(struct ipv6hdr) <= skb_headlen(skb)) {
- sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr;
- sk->sk_v6_daddr = ipv6_hdr(skb)->daddr;
+ if (skb_headlen(skb) < sizeof(struct ipv6hdr)) {
+ ret = -EINVAL;
+ goto out;
}
+ sk->sk_family = AF_INET6;
+ sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr;
+ sk->sk_v6_daddr = ipv6_hdr(skb)->daddr;
break;
#endif
default:
@@ -1156,6 +1160,21 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,
skb->ip_summed = CHECKSUM_COMPLETE;
}
+ if (prog->type == BPF_PROG_TYPE_LWT_XMIT) {
+ if (!ipv6_bpf_stub) {
+ pr_warn_once("Please test this program with the IPv6 module loaded\n");
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+#if IS_ENABLED(CONFIG_IPV6)
+ /* For CONFIG_IPV6=n, ipv6_bpf_stub is NULL which is
+ * handled by the above if statement.
+ */
+ dst_hold(&net->ipv6.ip6_null_entry->dst);
+ skb_dst_set(skb, &net->ipv6.ip6_null_entry->dst);
+#endif
+ }
+
ret = bpf_test_run(prog, skb, repeat, &retval, &duration, false);
if (ret)
goto out;
diff --git a/net/ceph/auth_x.c b/net/ceph/auth_x.c
index 692e0b868822..9e64e82d0b63 100644
--- a/net/ceph/auth_x.c
+++ b/net/ceph/auth_x.c
@@ -115,6 +115,11 @@ static int __ceph_x_decrypt(const struct ceph_crypto_key *key, int usage_slot,
if (ret)
return ret;
+ if (plaintext_len < sizeof(*hdr)) {
+ pr_err("%s plaintext too small %d\n", __func__, plaintext_len);
+ return -EINVAL;
+ }
+
hdr = p + ceph_crypt_data_offset(key);
if (le64_to_cpu(hdr->magic) != CEPHX_ENC_MAGIC) {
pr_err("%s bad magic\n", __func__);
diff --git a/net/ceph/crush/crush.c b/net/ceph/crush/crush.c
index 254ded0b05f6..521aec1d5fc0 100644
--- a/net/ceph/crush/crush.c
+++ b/net/ceph/crush/crush.c
@@ -47,7 +47,6 @@ int crush_get_bucket_item_weight(const struct crush_bucket *b, int p)
void crush_destroy_bucket_uniform(struct crush_bucket_uniform *b)
{
kfree(b->h.items);
- kfree(b);
}
void crush_destroy_bucket_list(struct crush_bucket_list *b)
@@ -55,14 +54,12 @@ void crush_destroy_bucket_list(struct crush_bucket_list *b)
kfree(b->item_weights);
kfree(b->sum_weights);
kfree(b->h.items);
- kfree(b);
}
void crush_destroy_bucket_tree(struct crush_bucket_tree *b)
{
kfree(b->h.items);
kfree(b->node_weights);
- kfree(b);
}
void crush_destroy_bucket_straw(struct crush_bucket_straw *b)
@@ -70,14 +67,12 @@ void crush_destroy_bucket_straw(struct crush_bucket_straw *b)
kfree(b->straws);
kfree(b->item_weights);
kfree(b->h.items);
- kfree(b);
}
void crush_destroy_bucket_straw2(struct crush_bucket_straw2 *b)
{
kfree(b->item_weights);
kfree(b->h.items);
- kfree(b);
}
void crush_destroy_bucket(struct crush_bucket *b)
@@ -99,6 +94,7 @@ void crush_destroy_bucket(struct crush_bucket *b)
crush_destroy_bucket_straw2((struct crush_bucket_straw2 *)b);
break;
}
+ kfree(b);
}
/**
diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
index c89e66d4fcb7..12658142e525 100644
--- a/net/ceph/osdmap.c
+++ b/net/ceph/osdmap.c
@@ -389,11 +389,15 @@ static int decode_choose_args(void **p, void *end, struct crush_map *c)
goto fail;
if (arg->ids_size &&
- arg->ids_size != c->buckets[bucket_index]->size)
+ (!c->buckets[bucket_index] ||
+ arg->ids_size != c->buckets[bucket_index]->size))
goto e_inval;
}
- insert_choose_arg_map(&c->choose_args, arg_map);
+ if (!__insert_choose_arg_map(&c->choose_args, arg_map)) {
+ ret = -EEXIST;
+ goto fail;
+ }
}
return 0;
@@ -516,6 +520,10 @@ static struct crush_map *crush_decode(void *pbyval, void *end)
b->id = ceph_decode_32(p);
b->type = ceph_decode_16(p);
b->alg = ceph_decode_8(p);
+ if (b->alg != alg) {
+ b->alg = 0;
+ goto bad;
+ }
b->hash = ceph_decode_8(p);
b->weight = ceph_decode_32(p);
b->size = ceph_decode_32(p);
@@ -1702,7 +1710,7 @@ static int osdmap_decode(void **p, void *end, bool msgr2,
ceph_decode_need(p, end, 3*sizeof(u32) +
map->max_osd*(struct_v >= 5 ? sizeof(u32) :
sizeof(u8)) +
- sizeof(*map->osd_weight), e_inval);
+ map->max_osd*sizeof(*map->osd_weight), e_inval);
if (ceph_decode_32(p) != map->max_osd)
goto e_inval;
diff --git a/net/core/dev.c b/net/core/dev.c
index 831129f2a69b..e4fcf09ba2be 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4103,15 +4103,16 @@ struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *d
}
EXPORT_SYMBOL_GPL(validate_xmit_skb_list);
-static void qdisc_pkt_len_segs_init(struct sk_buff *skb)
+static enum skb_drop_reason qdisc_pkt_len_segs_init(struct sk_buff *skb)
{
struct skb_shared_info *shinfo = skb_shinfo(skb);
+ unsigned int hdr_len, tlen;
u16 gso_segs;
qdisc_skb_cb(skb)->pkt_len = skb->len;
if (!shinfo->gso_size) {
qdisc_skb_cb(skb)->pkt_segs = 1;
- return;
+ return SKB_NOT_DROPPED_YET;
}
qdisc_skb_cb(skb)->pkt_segs = gso_segs = shinfo->gso_segs;
@@ -4119,44 +4120,49 @@ static void qdisc_pkt_len_segs_init(struct sk_buff *skb)
/* To get more precise estimation of bytes sent on wire,
* we add to pkt_len the headers size of all segments
*/
- if (skb_transport_header_was_set(skb)) {
- unsigned int hdr_len;
-
- /* mac layer + network layer */
- if (!skb->encapsulation)
- hdr_len = skb_transport_offset(skb);
- else
- hdr_len = skb_inner_transport_offset(skb);
- /* + transport layer */
- if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) {
- const struct tcphdr *th;
- struct tcphdr _tcphdr;
+ /* mac layer + network layer */
+ if (!skb->encapsulation) {
+ if (unlikely(!skb_transport_header_was_set(skb)))
+ return SKB_NOT_DROPPED_YET;
+ hdr_len = skb_transport_offset(skb);
+ } else {
+ hdr_len = skb_inner_transport_offset(skb);
+ }
+ /* + transport layer */
+ if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) {
+ const struct tcphdr *th;
- th = skb_header_pointer(skb, hdr_len,
- sizeof(_tcphdr), &_tcphdr);
- if (likely(th))
- hdr_len += __tcp_hdrlen(th);
- } else if (shinfo->gso_type & SKB_GSO_UDP_L4) {
- struct udphdr _udphdr;
+ if (!pskb_may_pull(skb, hdr_len + sizeof(struct tcphdr)))
+ return SKB_DROP_REASON_SKB_BAD_GSO;
- if (skb_header_pointer(skb, hdr_len,
- sizeof(_udphdr), &_udphdr))
- hdr_len += sizeof(struct udphdr);
- }
+ th = (const struct tcphdr *)(skb->data + hdr_len);
+ tlen = __tcp_hdrlen(th);
+ if (tlen < sizeof(*th))
+ return SKB_DROP_REASON_SKB_BAD_GSO;
+ hdr_len += tlen;
+ if (!pskb_may_pull(skb, hdr_len))
+ return SKB_DROP_REASON_SKB_BAD_GSO;
+ } else if (shinfo->gso_type & SKB_GSO_UDP_L4) {
+ if (!pskb_may_pull(skb, hdr_len + sizeof(struct udphdr)))
+ return SKB_DROP_REASON_SKB_BAD_GSO;
+ hdr_len += sizeof(struct udphdr);
+ }
- if (unlikely(shinfo->gso_type & SKB_GSO_DODGY)) {
- int payload = skb->len - hdr_len;
+ /* prior pskb_may_pull() might have changed skb->head. */
+ shinfo = skb_shinfo(skb);
+ if (unlikely(shinfo->gso_type & SKB_GSO_DODGY)) {
+ int payload = skb->len - hdr_len;
- /* Malicious packet. */
- if (payload <= 0)
- return;
- gso_segs = DIV_ROUND_UP(payload, shinfo->gso_size);
- shinfo->gso_segs = gso_segs;
- qdisc_skb_cb(skb)->pkt_segs = gso_segs;
- }
- qdisc_skb_cb(skb)->pkt_len += (gso_segs - 1) * hdr_len;
+ /* Malicious packet. */
+ if (payload <= 0)
+ return SKB_DROP_REASON_SKB_BAD_GSO;
+ gso_segs = DIV_ROUND_UP(payload, shinfo->gso_size);
+ shinfo->gso_segs = gso_segs;
+ qdisc_skb_cb(skb)->pkt_segs = gso_segs;
}
+ qdisc_skb_cb(skb)->pkt_len += (gso_segs - 1) * hdr_len;
+ return SKB_NOT_DROPPED_YET;
}
static int dev_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *q,
@@ -4761,9 +4767,10 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev)
{
struct net_device *dev = skb->dev;
struct netdev_queue *txq = NULL;
- struct Qdisc *q;
- int rc = -ENOMEM;
+ enum skb_drop_reason reason;
+ int cpu, rc = -ENOMEM;
bool again = false;
+ struct Qdisc *q;
skb_reset_mac_header(skb);
skb_assert_len(skb);
@@ -4772,6 +4779,12 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev)
(SKBTX_SCHED_TSTAMP | SKBTX_BPF)))
__skb_tstamp_tx(skb, NULL, NULL, skb->sk, SCM_TSTAMP_SCHED);
+ reason = qdisc_pkt_len_segs_init(skb);
+ if (unlikely(reason)) {
+ dev_core_stats_tx_dropped_inc(dev);
+ kfree_skb_reason(skb, reason);
+ return -EINVAL;
+ }
/* Disable soft irqs for various locks below. Also
* stops preemption for RCU.
*/
@@ -4779,7 +4792,6 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev)
skb_update_prio(skb);
- qdisc_pkt_len_segs_init(skb);
tcx_set_ingress(skb, false);
#ifdef CONFIG_NET_EGRESS
if (static_branch_unlikely(&egress_needed_key)) {
@@ -4832,59 +4844,61 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev)
* Check this and shot the lock. It is not prone from deadlocks.
*Either shot noqueue qdisc, it is even simpler 8)
*/
- if (dev->flags & IFF_UP) {
- int cpu = smp_processor_id(); /* ok because BHs are off */
+ if (unlikely(!(dev->flags & IFF_UP))) {
+ reason = SKB_DROP_REASON_DEV_READY;
+ goto drop;
+ }
- if (!netif_tx_owned(txq, cpu)) {
- bool is_list = false;
+ cpu = smp_processor_id(); /* ok because BHs are off */
- if (dev_xmit_recursion())
- goto recursion_alert;
+ if (likely(!netif_tx_owned(txq, cpu))) {
+ bool is_list = false;
- skb = validate_xmit_skb(skb, dev, &again);
- if (!skb)
- goto out;
+ if (dev_xmit_recursion())
+ goto recursion_alert;
- HARD_TX_LOCK(dev, txq, cpu);
+ skb = validate_xmit_skb(skb, dev, &again);
+ if (!skb)
+ goto out;
- if (!netif_xmit_stopped(txq)) {
- is_list = !!skb->next;
+ HARD_TX_LOCK(dev, txq, cpu);
- dev_xmit_recursion_inc();
- skb = dev_hard_start_xmit(skb, dev, txq, &rc);
- dev_xmit_recursion_dec();
+ if (!netif_xmit_stopped(txq)) {
+ is_list = !!skb->next;
- /* GSO segments a single SKB into
- * a list of frames. TCP expects error
- * to mean none of the data was sent.
- */
- if (is_list)
- rc = NETDEV_TX_OK;
- }
- HARD_TX_UNLOCK(dev, txq);
- if (!skb) /* xmit completed */
- goto out;
+ dev_xmit_recursion_inc();
+ skb = dev_hard_start_xmit(skb, dev, txq, &rc);
+ dev_xmit_recursion_dec();
- net_crit_ratelimited("Virtual device %s asks to queue packet!\n",
- dev->name);
- /* NETDEV_TX_BUSY or queue was stopped */
- if (!is_list)
- rc = -ENETDOWN;
- } else {
- /* Recursion is detected! It is possible,
- * unfortunately
+ /* GSO segments a single SKB into a list of frames.
+ * TCP expects error to mean none of the data was sent.
*/
-recursion_alert:
- net_crit_ratelimited("Dead loop on virtual device %s, fix it urgently!\n",
- dev->name);
- rc = -ENETDOWN;
+ if (is_list)
+ rc = NETDEV_TX_OK;
}
+ HARD_TX_UNLOCK(dev, txq);
+ if (!skb) /* xmit completed */
+ goto out;
+
+ net_crit_ratelimited("Virtual device %s asks to queue packet!\n",
+ dev->name);
+ /* NETDEV_TX_BUSY or queue was stopped */
+ if (!is_list)
+ rc = -ENETDOWN;
+ } else {
+ /* Recursion is detected! It is possible unfortunately. */
+recursion_alert:
+ net_crit_ratelimited("Dead loop on virtual device %s, fix it urgently!\n",
+ dev->name);
+ rc = -ENETDOWN;
}
+ reason = SKB_DROP_REASON_RECURSION_LIMIT;
+drop:
rcu_read_unlock_bh();
dev_core_stats_tx_dropped_inc(dev);
- kfree_skb_list(skb);
+ kfree_skb_list_reason(skb, reason);
return rc;
out:
rcu_read_unlock_bh();
diff --git a/net/core/filter.c b/net/core/filter.c
index 78b548158fb0..d8a853a61b53 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -508,7 +508,7 @@ static bool convert_bpf_ld_abs(struct sock_filter *fp, struct bpf_insn **insnp)
((unaligned_ok && offset >= 0) ||
(!unaligned_ok && offset >= 0 &&
offset + ip_align >= 0 &&
- offset + ip_align % size == 0))) {
+ (offset + ip_align) % size == 0))) {
bool ldx_off_ok = offset <= S16_MAX;
*insn++ = BPF_MOV64_REG(BPF_REG_TMP, BPF_REG_H);
@@ -4395,6 +4395,8 @@ u32 xdp_master_redirect(struct xdp_buff *xdp)
struct net_device *master, *slave;
master = netdev_master_upper_dev_get_rcu(xdp->rxq->dev);
+ if (unlikely(!(master->flags & IFF_UP)))
+ return XDP_ABORTED;
slave = master->netdev_ops->ndo_xdp_get_xmit_slave(master, xdp);
if (slave && slave != xdp->rxq->dev) {
/* The target device is different from the receiving device, so
@@ -5395,7 +5397,7 @@ static int bpf_sol_tcp_setsockopt(struct sock *sk, int optname,
if (val <= 0)
return -EINVAL;
tp->snd_cwnd_clamp = val;
- tp->snd_ssthresh = val;
+ WRITE_ONCE(tp->snd_ssthresh, val);
break;
case TCP_BPF_DELACK_MAX:
timeout = usecs_to_jiffies(val);
@@ -10581,10 +10583,11 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type,
si->dst_reg, si->dst_reg, \
offsetof(OBJ, OBJ_FIELD)); \
if (si->dst_reg == si->src_reg) { \
- *insn++ = BPF_JMP_A(1); \
+ *insn++ = BPF_JMP_A(2); \
*insn++ = BPF_LDX_MEM(BPF_DW, reg, si->src_reg, \
offsetof(struct bpf_sock_ops_kern, \
temp)); \
+ *insn++ = BPF_MOV64_IMM(si->dst_reg, 0); \
} \
} while (0)
@@ -10618,10 +10621,11 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type,
si->dst_reg, si->src_reg, \
offsetof(struct bpf_sock_ops_kern, sk));\
if (si->dst_reg == si->src_reg) { \
- *insn++ = BPF_JMP_A(1); \
+ *insn++ = BPF_JMP_A(2); \
*insn++ = BPF_LDX_MEM(BPF_DW, reg, si->src_reg, \
offsetof(struct bpf_sock_ops_kern, \
temp)); \
+ *insn++ = BPF_MOV64_IMM(si->dst_reg, 0); \
} \
} while (0)
diff --git a/net/core/gro.c b/net/core/gro.c
index 31d21de5b15a..9f8960789b2c 100644
--- a/net/core/gro.c
+++ b/net/core/gro.c
@@ -213,10 +213,12 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb)
p->data_len += len;
p->truesize += delta_truesize;
p->len += len;
+ skb_shinfo(p)->flags |= skbinfo->flags & SKBFL_SHARED_FRAG;
if (lp != p) {
lp->data_len += len;
lp->truesize += delta_truesize;
lp->len += len;
+ skb_shinfo(lp)->flags |= skbinfo->flags & SKBFL_SHARED_FRAG;
}
NAPI_GRO_CB(skb)->same_flow = 1;
return 0;
@@ -244,6 +246,8 @@ int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb)
p->truesize += skb->truesize;
p->len += skb->len;
+ skb_shinfo(p)->flags |= skb_shinfo(skb)->flags & SKBFL_SHARED_FRAG;
+
NAPI_GRO_CB(skb)->same_flow = 1;
return 0;
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index c56a4e7bf790..5a9cc7268521 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -3211,8 +3211,10 @@ int neigh_xmit(int index, struct net_device *dev,
rcu_read_lock();
tbl = rcu_dereference(neigh_tables[index]);
- if (!tbl)
- goto out_unlock;
+ if (!tbl) {
+ rcu_read_unlock();
+ goto out_kfree_skb;
+ }
if (index == NEIGH_ARP_TABLE) {
u32 key = *((u32 *)addr);
@@ -3228,7 +3230,6 @@ int neigh_xmit(int index, struct net_device *dev,
goto out_kfree_skb;
}
err = READ_ONCE(neigh->output)(neigh, skb);
-out_unlock:
rcu_read_unlock();
}
else if (index == NEIGH_LINK_TABLE) {
@@ -3238,11 +3239,10 @@ int neigh_xmit(int index, struct net_device *dev,
goto out_kfree_skb;
err = dev_queue_xmit(skb);
}
-out:
return err;
out_kfree_skb:
kfree_skb(skb);
- goto out;
+ return err;
}
EXPORT_SYMBOL(neigh_xmit);
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 5ae90c14ba49..84faace50ac2 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -706,6 +706,23 @@ static int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev)
return 0;
}
+/*
+ * Test whether the caller left np->local_ip unset, so that
+ * netpoll_setup() should auto-populate it from the egress device.
+ *
+ * np->local_ip is a union of __be32 (IPv4) and struct in6_addr (IPv6),
+ * so an IPv6 address whose first 4 bytes are zero (e.g. ::1, ::2,
+ * IPv4-mapped ::ffff:a.b.c.d) must not be tested via the IPv4 arm —
+ * doing so would misclassify a caller-supplied address as unset and
+ * silently overwrite it with whatever address the device exposes.
+ */
+static bool netpoll_local_ip_unset(const struct netpoll *np)
+{
+ if (np->ipv6)
+ return ipv6_addr_any(&np->local_ip.in6);
+ return !np->local_ip.ip;
+}
+
int netpoll_setup(struct netpoll *np)
{
struct net *net = current->nsproxy->net_ns;
@@ -750,7 +767,7 @@ int netpoll_setup(struct netpoll *np)
rtnl_lock();
}
- if (!np->local_ip.ip) {
+ if (netpoll_local_ip_unset(np)) {
if (!np->ipv6) {
err = netpoll_take_ipv4(np, ndev);
if (err)
diff --git a/net/core/page_pool.c b/net/core/page_pool.c
index 265a729431bb..8171d1173221 100644
--- a/net/core/page_pool.c
+++ b/net/core/page_pool.c
@@ -327,6 +327,11 @@ static void page_pool_uninit(struct page_pool *pool)
if (!pool->system)
free_percpu(pool->recycle_stats);
#endif
+
+ if (pool->mp_ops) {
+ pool->mp_ops->destroy(pool);
+ static_branch_dec(&page_pool_mem_providers);
+ }
}
/**
@@ -1126,11 +1131,6 @@ static void __page_pool_destroy(struct page_pool *pool)
page_pool_unlist(pool);
page_pool_uninit(pool);
- if (pool->mp_ops) {
- pool->mp_ops->destroy(pool);
- static_branch_dec(&page_pool_mem_providers);
- }
-
kfree(pool);
}
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 43ee86dcf2ea..28bd8304796d 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2258,6 +2258,7 @@ struct sk_buff *__pskb_copy_fclone(struct sk_buff *skb, int headroom,
skb_frag_ref(skb, i);
}
skb_shinfo(n)->nr_frags = i;
+ skb_shinfo(n)->flags |= skb_shinfo(skb)->flags & SKBFL_SHARED_FRAG;
}
if (skb_has_frag_list(skb)) {
@@ -4373,6 +4374,8 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen)
tgt->ip_summed = CHECKSUM_PARTIAL;
skb->ip_summed = CHECKSUM_PARTIAL;
+ skb_shinfo(tgt)->flags |= skb_shinfo(skb)->flags & SKBFL_SHARED_FRAG;
+
skb_len_add(skb, -shiftlen);
skb_len_add(tgt, shiftlen);
@@ -4983,7 +4986,8 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
skb_copy_from_linear_data_offset(head_skb, offset,
skb_put(nskb, hsize), hsize);
- skb_shinfo(nskb)->flags |= skb_shinfo(head_skb)->flags &
+ skb_shinfo(nskb)->flags |= (skb_shinfo(head_skb)->flags |
+ skb_shinfo(frag_skb)->flags) &
SKBFL_SHARED_FRAG;
if (skb_zerocopy_clone(nskb, frag_skb, GFP_ATOMIC))
@@ -5000,6 +5004,9 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
nfrags = skb_shinfo(list_skb)->nr_frags;
frag = skb_shinfo(list_skb)->frags;
frag_skb = list_skb;
+
+ skb_shinfo(nskb)->flags |= skb_shinfo(frag_skb)->flags & SKBFL_SHARED_FRAG;
+
if (!skb_headlen(list_skb)) {
BUG_ON(!nfrags);
} else {
@@ -5142,7 +5149,7 @@ static const u8 skb_ext_type_len[] = {
#endif
};
-static __always_inline unsigned int skb_ext_total_length(void)
+static __always_inline __no_profile unsigned int skb_ext_total_length(void)
{
unsigned int l = SKB_EXT_CHUNKSIZEOF(struct skb_ext);
int i;
@@ -5156,9 +5163,7 @@ static __always_inline unsigned int skb_ext_total_length(void)
static void skb_extensions_init(void)
{
BUILD_BUG_ON(SKB_EXT_NUM > 8);
-#if !IS_ENABLED(CONFIG_KCOV_INSTRUMENT_ALL)
BUILD_BUG_ON(skb_ext_total_length() > 255);
-#endif
skbuff_ext_cache = kmem_cache_create("skbuff_ext_cache",
SKB_EXT_ALIGN_VALUE * skb_ext_total_length(),
@@ -6226,6 +6231,8 @@ bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,
from_shinfo->frags,
from_shinfo->nr_frags * sizeof(skb_frag_t));
to_shinfo->nr_frags += from_shinfo->nr_frags;
+ if (from_shinfo->nr_frags)
+ to_shinfo->flags |= from_shinfo->flags & SKBFL_SHARED_FRAG;
if (!skb_cloned(from))
from_shinfo->nr_frags = 0;
diff --git a/net/dsa/conduit.c b/net/dsa/conduit.c
index a1b044467bd6..8398d72d7e4d 100644
--- a/net/dsa/conduit.c
+++ b/net/dsa/conduit.c
@@ -27,9 +27,7 @@ static int dsa_conduit_get_regs_len(struct net_device *dev)
int len;
if (ops && ops->get_regs_len) {
- netdev_lock_ops(dev);
len = ops->get_regs_len(dev);
- netdev_unlock_ops(dev);
if (len < 0)
return len;
ret += len;
@@ -60,15 +58,11 @@ static void dsa_conduit_get_regs(struct net_device *dev,
int len;
if (ops && ops->get_regs_len && ops->get_regs) {
- netdev_lock_ops(dev);
len = ops->get_regs_len(dev);
- if (len < 0) {
- netdev_unlock_ops(dev);
+ if (len < 0)
return;
- }
regs->len = len;
ops->get_regs(dev, regs, data);
- netdev_unlock_ops(dev);
data += regs->len;
}
@@ -115,10 +109,8 @@ static void dsa_conduit_get_ethtool_stats(struct net_device *dev,
int count, mcount = 0;
if (ops && ops->get_sset_count && ops->get_ethtool_stats) {
- netdev_lock_ops(dev);
mcount = ops->get_sset_count(dev, ETH_SS_STATS);
ops->get_ethtool_stats(dev, stats, data);
- netdev_unlock_ops(dev);
}
list_for_each_entry(dp, &dst->ports, list) {
@@ -149,10 +141,8 @@ static void dsa_conduit_get_ethtool_phy_stats(struct net_device *dev,
if (count >= 0)
phy_ethtool_get_stats(dev->phydev, stats, data);
} else if (ops && ops->get_sset_count && ops->get_ethtool_phy_stats) {
- netdev_lock_ops(dev);
count = ops->get_sset_count(dev, ETH_SS_PHY_STATS);
ops->get_ethtool_phy_stats(dev, stats, data);
- netdev_unlock_ops(dev);
}
if (count < 0)
@@ -176,13 +166,11 @@ static int dsa_conduit_get_sset_count(struct net_device *dev, int sset)
struct dsa_switch_tree *dst = cpu_dp->dst;
int count = 0;
- netdev_lock_ops(dev);
if (sset == ETH_SS_PHY_STATS && dev->phydev &&
(!ops || !ops->get_ethtool_phy_stats))
count = phy_ethtool_get_sset_count(dev->phydev);
else if (ops && ops->get_sset_count)
count = ops->get_sset_count(dev, sset);
- netdev_unlock_ops(dev);
if (count < 0)
count = 0;
@@ -239,7 +227,6 @@ static void dsa_conduit_get_strings(struct net_device *dev, u32 stringset,
struct dsa_switch_tree *dst = cpu_dp->dst;
int count, mcount = 0;
- netdev_lock_ops(dev);
if (stringset == ETH_SS_PHY_STATS && dev->phydev &&
!ops->get_ethtool_phy_stats) {
mcount = phy_ethtool_get_sset_count(dev->phydev);
@@ -253,7 +240,6 @@ static void dsa_conduit_get_strings(struct net_device *dev, u32 stringset,
mcount = 0;
ops->get_strings(dev, stringset, data);
}
- netdev_unlock_ops(dev);
list_for_each_entry(dp, &dst->ports, list) {
if (!dsa_port_is_dsa(dp) && !dsa_port_is_cpu(dp))
diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c
index 5683c328990f..f430d6f0463e 100644
--- a/net/ipv4/ip_tunnel_core.c
+++ b/net/ipv4/ip_tunnel_core.c
@@ -65,7 +65,7 @@ void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
DEV_STATS_INC(dev, tx_errors);
}
ip_rt_put(rt);
- kfree_skb(skb);
+ kfree_skb_reason(skb, SKB_DROP_REASON_RECURSION_LIMIT);
return;
}
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 1cdd9c28ab2d..97ead883e4a1 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -110,13 +110,25 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
arpptr += dev->addr_len;
memcpy(&src_ipaddr, arpptr, sizeof(u32));
arpptr += sizeof(u32);
- tgt_devaddr = arpptr;
- arpptr += dev->addr_len;
+
+ if (IS_ENABLED(CONFIG_FIREWIRE_NET) && dev->type == ARPHRD_IEEE1394) {
+ if (unlikely(memchr_inv(arpinfo->tgt_devaddr.mask, 0,
+ sizeof(arpinfo->tgt_devaddr.mask))))
+ return 0;
+
+ tgt_devaddr = NULL;
+ } else {
+ tgt_devaddr = arpptr;
+ arpptr += dev->addr_len;
+ }
memcpy(&tgt_ipaddr, arpptr, sizeof(u32));
if (NF_INVF(arpinfo, ARPT_INV_SRCDEVADDR,
arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr,
- dev->addr_len)) ||
+ dev->addr_len)))
+ return 0;
+
+ if (tgt_devaddr &&
NF_INVF(arpinfo, ARPT_INV_TGTDEVADDR,
arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr,
dev->addr_len)))
diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c
index a4e07e5e9c11..f65dd339208e 100644
--- a/net/ipv4/netfilter/arpt_mangle.c
+++ b/net/ipv4/netfilter/arpt_mangle.c
@@ -40,6 +40,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par)
}
arpptr += pln;
if (mangle->flags & ARPT_MANGLE_TDEV) {
+ if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) &&
+ skb->dev->type == ARPHRD_IEEE1394))
+ return NF_DROP;
+
if (ARPT_DEV_ADDR_LEN_MAX < hln ||
(arpptr + hln > skb_tail_pointer(skb)))
return NF_DROP;
@@ -47,6 +51,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par)
}
arpptr += hln;
if (mangle->flags & ARPT_MANGLE_TIP) {
+ if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) &&
+ skb->dev->type == ARPHRD_IEEE1394))
+ return NF_DROP;
+
if (ARPT_MANGLE_ADDR_LEN_MAX < pln ||
(arpptr + pln > skb_tail_pointer(skb)))
return NF_DROP;
diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c
index a5db7c67d61b..625a1ca13b1b 100644
--- a/net/ipv4/netfilter/iptable_nat.c
+++ b/net/ipv4/netfilter/iptable_nat.c
@@ -79,7 +79,7 @@ static int ipt_nat_register_lookups(struct net *net)
while (i)
nf_nat_ipv4_unregister_fn(net, &ops[--i]);
- kfree(ops);
+ kfree_rcu(ops, rcu);
return ret;
}
}
@@ -100,7 +100,7 @@ static void ipt_nat_unregister_lookups(struct net *net)
for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++)
nf_nat_ipv4_unregister_fn(net, &ops[i]);
- kfree(ops);
+ kfree_rcu(ops, rcu);
}
static int iptable_nat_table_init(struct net *net)
diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c
index 2c9036c719b6..11a763cbc848 100644
--- a/net/ipv4/nexthop.c
+++ b/net/ipv4/nexthop.c
@@ -2466,10 +2466,10 @@ static int replace_nexthop_single(struct net *net, struct nexthop *old,
goto err_notify;
}
- /* When replacing an IPv4 nexthop with an IPv6 nexthop, potentially
+ /* When replacing a nexthop with one of a different family, potentially
* update IPv4 indication in all the groups using the nexthop.
*/
- if (oldi->family == AF_INET && newi->family == AF_INET6) {
+ if (oldi->family != newi->family) {
list_for_each_entry(nhge, &old->grp_list, nh_list) {
struct nexthop *nhp = nhge->nh_parent;
struct nh_group *nhg;
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index fc3affd9c801..b5f0a65c6786 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -286,7 +286,6 @@ static int cookie_tcp_reqsk_init(struct sock *sk, struct sk_buff *skb,
treq->rcv_isn = ntohl(th->seq) - 1;
treq->snt_isn = ntohl(th->ack_seq) - 1;
treq->syn_tos = TCP_SKB_CB(skb)->ip_dsfield;
- treq->req_usec_ts = false;
#if IS_ENABLED(CONFIG_MPTCP)
treq->is_mptcp = sk_is_mptcp(sk);
@@ -349,6 +348,7 @@ struct request_sock *cookie_tcp_reqsk_alloc(const struct request_sock_ops *ops,
ireq->wscale_ok = tcp_opt->wscale_ok;
ireq->ecn_ok = !!(tcp_opt->rcv_tsecr & TS_OPT_ECN);
+ treq->req_usec_ts = false;
treq->ts_off = tsoff;
return req;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 202a4e57a218..cee51749df16 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -3458,7 +3458,7 @@ int tcp_disconnect(struct sock *sk, int flags)
icsk->icsk_rto = TCP_TIMEOUT_INIT;
WRITE_ONCE(icsk->icsk_rto_min, TCP_RTO_MIN);
WRITE_ONCE(icsk->icsk_delack_max, TCP_DELACK_MAX);
- tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
+ WRITE_ONCE(tp->snd_ssthresh, TCP_INFINITE_SSTHRESH);
tcp_snd_cwnd_set(tp, TCP_INIT_CWND);
tp->snd_cwnd_cnt = 0;
tp->is_cwnd_limited = 0;
@@ -3656,7 +3656,8 @@ static void tcp_enable_tx_delay(struct sock *sk, int val)
if (delta && sk->sk_state == TCP_ESTABLISHED) {
s64 srtt = (s64)tp->srtt_us + delta;
- tp->srtt_us = clamp_t(s64, srtt, 1, ~0U);
+ WRITE_ONCE(tp->srtt_us,
+ clamp_t(s64, srtt, 1, ~0U));
/* Note: does not deal with non zero icsk_backoff */
tcp_set_rto(sk);
@@ -4225,12 +4226,18 @@ static void tcp_get_info_chrono_stats(const struct tcp_sock *tp,
struct tcp_info *info)
{
u64 stats[__TCP_CHRONO_MAX], total = 0;
- enum tcp_chrono i;
+ enum tcp_chrono i, cur;
+ /* Following READ_ONCE()s pair with WRITE_ONCE()s in tcp_chrono_set().
+ * This is because socket lock might not be owned by us at this point.
+ * This is best effort, tcp_get_timestamping_opt_stats() can
+ * see wrong values. A real fix would be too costly for TCP fast path.
+ */
+ cur = READ_ONCE(tp->chrono_type);
for (i = TCP_CHRONO_BUSY; i < __TCP_CHRONO_MAX; ++i) {
- stats[i] = tp->chrono_stat[i - 1];
- if (i == tp->chrono_type)
- stats[i] += tcp_jiffies32 - tp->chrono_start;
+ stats[i] = READ_ONCE(tp->chrono_stat[i - 1]);
+ if (i == cur)
+ stats[i] += tcp_jiffies32 - READ_ONCE(tp->chrono_start);
stats[i] *= USEC_PER_SEC / HZ;
total += stats[i];
}
@@ -4462,9 +4469,9 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk,
nla_put_u64_64bit(stats, TCP_NLA_SNDBUF_LIMITED,
info.tcpi_sndbuf_limited, TCP_NLA_PAD);
nla_put_u64_64bit(stats, TCP_NLA_DATA_SEGS_OUT,
- tp->data_segs_out, TCP_NLA_PAD);
+ READ_ONCE(tp->data_segs_out), TCP_NLA_PAD);
nla_put_u64_64bit(stats, TCP_NLA_TOTAL_RETRANS,
- tp->total_retrans, TCP_NLA_PAD);
+ READ_ONCE(tp->total_retrans), TCP_NLA_PAD);
rate = READ_ONCE(sk->sk_pacing_rate);
rate64 = (rate != ~0UL) ? rate : ~0ULL;
@@ -4473,37 +4480,42 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk,
rate64 = tcp_compute_delivery_rate(tp);
nla_put_u64_64bit(stats, TCP_NLA_DELIVERY_RATE, rate64, TCP_NLA_PAD);
- nla_put_u32(stats, TCP_NLA_SND_CWND, tcp_snd_cwnd(tp));
- nla_put_u32(stats, TCP_NLA_REORDERING, tp->reordering);
- nla_put_u32(stats, TCP_NLA_MIN_RTT, tcp_min_rtt(tp));
+ nla_put_u32(stats, TCP_NLA_SND_CWND, READ_ONCE(tp->snd_cwnd));
+ nla_put_u32(stats, TCP_NLA_REORDERING, READ_ONCE(tp->reordering));
+ nla_put_u32(stats, TCP_NLA_MIN_RTT, data_race(tcp_min_rtt(tp)));
nla_put_u8(stats, TCP_NLA_RECUR_RETRANS,
READ_ONCE(inet_csk(sk)->icsk_retransmits));
- nla_put_u8(stats, TCP_NLA_DELIVERY_RATE_APP_LMT, !!tp->rate_app_limited);
- nla_put_u32(stats, TCP_NLA_SND_SSTHRESH, tp->snd_ssthresh);
- nla_put_u32(stats, TCP_NLA_DELIVERED, tp->delivered);
- nla_put_u32(stats, TCP_NLA_DELIVERED_CE, tp->delivered_ce);
-
- nla_put_u32(stats, TCP_NLA_SNDQ_SIZE, tp->write_seq - tp->snd_una);
+ nla_put_u8(stats, TCP_NLA_DELIVERY_RATE_APP_LMT, data_race(!!tp->rate_app_limited));
+ nla_put_u32(stats, TCP_NLA_SND_SSTHRESH, READ_ONCE(tp->snd_ssthresh));
+ nla_put_u32(stats, TCP_NLA_DELIVERED, READ_ONCE(tp->delivered));
+ nla_put_u32(stats, TCP_NLA_DELIVERED_CE, READ_ONCE(tp->delivered_ce));
+
+ nla_put_u32(stats, TCP_NLA_SNDQ_SIZE,
+ max_t(int, 0,
+ READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_una)));
nla_put_u8(stats, TCP_NLA_CA_STATE, inet_csk(sk)->icsk_ca_state);
- nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, tp->bytes_sent,
- TCP_NLA_PAD);
- nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, tp->bytes_retrans,
+ nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, READ_ONCE(tp->bytes_sent),
TCP_NLA_PAD);
- nla_put_u32(stats, TCP_NLA_DSACK_DUPS, tp->dsack_dups);
- nla_put_u32(stats, TCP_NLA_REORD_SEEN, tp->reord_seen);
- nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3);
- nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash);
+ nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS,
+ READ_ONCE(tp->bytes_retrans), TCP_NLA_PAD);
+ nla_put_u32(stats, TCP_NLA_DSACK_DUPS, READ_ONCE(tp->dsack_dups));
+ nla_put_u32(stats, TCP_NLA_REORD_SEEN, READ_ONCE(tp->reord_seen));
+ nla_put_u32(stats, TCP_NLA_SRTT, READ_ONCE(tp->srtt_us) >> 3);
+ nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH,
+ READ_ONCE(tp->timeout_rehash));
nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT,
- max_t(int, 0, tp->write_seq - tp->snd_nxt));
+ max_t(int, 0,
+ READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_nxt)));
nla_put_u64_64bit(stats, TCP_NLA_EDT, orig_skb->skb_mstamp_ns,
TCP_NLA_PAD);
if (ack_skb)
nla_put_u8(stats, TCP_NLA_TTL,
tcp_skb_ttl_or_hop_limit(ack_skb));
- nla_put_u32(stats, TCP_NLA_REHASH, tp->plb_rehash + tp->timeout_rehash);
+ nla_put_u32(stats, TCP_NLA_REHASH,
+ READ_ONCE(tp->plb_rehash) + READ_ONCE(tp->timeout_rehash));
return stats;
}
diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c
index 760941e55153..3df6160f5156 100644
--- a/net/ipv4/tcp_bbr.c
+++ b/net/ipv4/tcp_bbr.c
@@ -896,8 +896,8 @@ static void bbr_check_drain(struct sock *sk, const struct rate_sample *rs)
if (bbr->mode == BBR_STARTUP && bbr_full_bw_reached(sk)) {
bbr->mode = BBR_DRAIN; /* drain queue we created */
- tcp_sk(sk)->snd_ssthresh =
- bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT);
+ WRITE_ONCE(tcp_sk(sk)->snd_ssthresh,
+ bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT));
} /* fall through to check if in-flight is already small: */
if (bbr->mode == BBR_DRAIN &&
bbr_packets_in_net_at_edt(sk, tcp_packets_in_flight(tcp_sk(sk))) <=
@@ -1042,7 +1042,7 @@ __bpf_kfunc static void bbr_init(struct sock *sk)
struct bbr *bbr = inet_csk_ca(sk);
bbr->prior_cwnd = 0;
- tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
+ WRITE_ONCE(tp->snd_ssthresh, TCP_INFINITE_SSTHRESH);
bbr->rtt_cnt = 0;
bbr->next_rtt_delivered = tp->delivered;
bbr->prev_ca_state = TCP_CA_Open;
diff --git a/net/ipv4/tcp_bic.c b/net/ipv4/tcp_bic.c
index 58358bf92e1b..65444ff14241 100644
--- a/net/ipv4/tcp_bic.c
+++ b/net/ipv4/tcp_bic.c
@@ -74,7 +74,7 @@ static void bictcp_init(struct sock *sk)
bictcp_reset(ca);
if (initial_ssthresh)
- tcp_sk(sk)->snd_ssthresh = initial_ssthresh;
+ WRITE_ONCE(tcp_sk(sk)->snd_ssthresh, initial_ssthresh);
}
/*
diff --git a/net/ipv4/tcp_cdg.c b/net/ipv4/tcp_cdg.c
index ceabfd690a29..0812c390aee5 100644
--- a/net/ipv4/tcp_cdg.c
+++ b/net/ipv4/tcp_cdg.c
@@ -162,7 +162,7 @@ static void tcp_cdg_hystart_update(struct sock *sk)
NET_ADD_STATS(sock_net(sk),
LINUX_MIB_TCPHYSTARTTRAINCWND,
tcp_snd_cwnd(tp));
- tp->snd_ssthresh = tcp_snd_cwnd(tp);
+ WRITE_ONCE(tp->snd_ssthresh, tcp_snd_cwnd(tp));
return;
}
}
@@ -181,7 +181,7 @@ static void tcp_cdg_hystart_update(struct sock *sk)
NET_ADD_STATS(sock_net(sk),
LINUX_MIB_TCPHYSTARTDELAYCWND,
tcp_snd_cwnd(tp));
- tp->snd_ssthresh = tcp_snd_cwnd(tp);
+ WRITE_ONCE(tp->snd_ssthresh, tcp_snd_cwnd(tp));
}
}
}
diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c
index 76c23675ae50..f891e8d1e545 100644
--- a/net/ipv4/tcp_cubic.c
+++ b/net/ipv4/tcp_cubic.c
@@ -136,7 +136,7 @@ __bpf_kfunc static void cubictcp_init(struct sock *sk)
bictcp_hystart_reset(sk);
if (!hystart && initial_ssthresh)
- tcp_sk(sk)->snd_ssthresh = initial_ssthresh;
+ WRITE_ONCE(tcp_sk(sk)->snd_ssthresh, initial_ssthresh);
}
__bpf_kfunc static void cubictcp_cwnd_event(struct sock *sk, enum tcp_ca_event event)
@@ -423,7 +423,7 @@ static void hystart_update(struct sock *sk, u32 delay)
NET_ADD_STATS(sock_net(sk),
LINUX_MIB_TCPHYSTARTTRAINCWND,
tcp_snd_cwnd(tp));
- tp->snd_ssthresh = tcp_snd_cwnd(tp);
+ WRITE_ONCE(tp->snd_ssthresh, tcp_snd_cwnd(tp));
}
}
}
@@ -443,7 +443,7 @@ static void hystart_update(struct sock *sk, u32 delay)
NET_ADD_STATS(sock_net(sk),
LINUX_MIB_TCPHYSTARTDELAYCWND,
tcp_snd_cwnd(tp));
- tp->snd_ssthresh = tcp_snd_cwnd(tp);
+ WRITE_ONCE(tp->snd_ssthresh, tcp_snd_cwnd(tp));
}
}
}
diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c
index 03abe0848420..6f103038b015 100644
--- a/net/ipv4/tcp_dctcp.c
+++ b/net/ipv4/tcp_dctcp.c
@@ -177,7 +177,7 @@ static void dctcp_react_to_loss(struct sock *sk)
struct tcp_sock *tp = tcp_sk(sk);
ca->loss_cwnd = tcp_snd_cwnd(tp);
- tp->snd_ssthresh = max(tcp_snd_cwnd(tp) >> 1U, 2U);
+ WRITE_ONCE(tp->snd_ssthresh, max(tcp_snd_cwnd(tp) >> 1U, 2U));
}
__bpf_kfunc static void dctcp_state(struct sock *sk, u8 new_state)
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index cba89733d121..cb4bcc5a8578 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -476,14 +476,14 @@ static bool tcp_accecn_process_option(struct tcp_sock *tp,
static void tcp_count_delivered_ce(struct tcp_sock *tp, u32 ecn_count)
{
- tp->delivered_ce += ecn_count;
+ WRITE_ONCE(tp->delivered_ce, tp->delivered_ce + ecn_count);
}
/* Updates the delivered and delivered_ce counts */
static void tcp_count_delivered(struct tcp_sock *tp, u32 delivered,
bool ece_ack)
{
- tp->delivered += delivered;
+ WRITE_ONCE(tp->delivered, tp->delivered + delivered);
if (tcp_ecn_mode_rfc3168(tp) && ece_ack)
tcp_count_delivered_ce(tp, delivered);
}
@@ -1133,7 +1133,7 @@ static void tcp_rtt_estimator(struct sock *sk, long mrtt_us)
tcp_bpf_rtt(sk, mrtt_us, srtt);
}
- tp->srtt_us = max(1U, srtt);
+ WRITE_ONCE(tp->srtt_us, max(1U, srtt));
}
void tcp_update_pacing_rate(struct sock *sk)
@@ -1247,7 +1247,7 @@ static u32 tcp_dsack_seen(struct tcp_sock *tp, u32 start_seq,
else if (tp->tlp_high_seq && tp->tlp_high_seq == end_seq)
state->flag |= FLAG_DSACK_TLP;
- tp->dsack_dups += dup_segs;
+ WRITE_ONCE(tp->dsack_dups, tp->dsack_dups + dup_segs);
/* Skip the DSACK if dup segs weren't retransmitted by sender */
if (tp->dsack_dups > tp->total_retrans)
return 0;
@@ -1294,12 +1294,13 @@ static void tcp_check_sack_reordering(struct sock *sk, const u32 low_seq,
tp->sacked_out,
tp->undo_marker ? tp->undo_retrans : 0);
#endif
- tp->reordering = min_t(u32, (metric + mss - 1) / mss,
- READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering));
+ WRITE_ONCE(tp->reordering,
+ min_t(u32, (metric + mss - 1) / mss,
+ READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering)));
}
/* This exciting event is worth to be remembered. 8) */
- tp->reord_seen++;
+ WRITE_ONCE(tp->reord_seen, tp->reord_seen + 1);
NET_INC_STATS(sock_net(sk),
ts ? LINUX_MIB_TCPTSREORDER : LINUX_MIB_TCPSACKREORDER);
}
@@ -2440,9 +2441,10 @@ static void tcp_check_reno_reordering(struct sock *sk, const int addend)
if (!tcp_limit_reno_sacked(tp))
return;
- tp->reordering = min_t(u32, tp->packets_out + addend,
- READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering));
- tp->reord_seen++;
+ WRITE_ONCE(tp->reordering,
+ min_t(u32, tp->packets_out + addend,
+ READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering)));
+ WRITE_ONCE(tp->reord_seen, tp->reord_seen + 1);
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRENOREORDER);
}
@@ -2566,7 +2568,7 @@ void tcp_enter_loss(struct sock *sk)
(icsk->icsk_ca_state == TCP_CA_Loss && !icsk->icsk_retransmits)) {
tp->prior_ssthresh = tcp_current_ssthresh(sk);
tp->prior_cwnd = tcp_snd_cwnd(tp);
- tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk);
+ WRITE_ONCE(tp->snd_ssthresh, icsk->icsk_ca_ops->ssthresh(sk));
tcp_ca_event(sk, CA_EVENT_LOSS);
tcp_init_undo(tp);
}
@@ -2580,8 +2582,8 @@ void tcp_enter_loss(struct sock *sk)
reordering = READ_ONCE(net->ipv4.sysctl_tcp_reordering);
if (icsk->icsk_ca_state <= TCP_CA_Disorder &&
tp->sacked_out >= reordering)
- tp->reordering = min_t(unsigned int, tp->reordering,
- reordering);
+ WRITE_ONCE(tp->reordering,
+ min_t(unsigned int, tp->reordering, reordering));
tcp_set_ca_state(sk, TCP_CA_Loss);
tp->high_seq = tp->snd_nxt;
@@ -2859,7 +2861,7 @@ static void tcp_undo_cwnd_reduction(struct sock *sk, bool unmark_loss)
tcp_snd_cwnd_set(tp, icsk->icsk_ca_ops->undo_cwnd(sk));
if (tp->prior_ssthresh > tp->snd_ssthresh) {
- tp->snd_ssthresh = tp->prior_ssthresh;
+ WRITE_ONCE(tp->snd_ssthresh, tp->prior_ssthresh);
tcp_ecn_withdraw_cwr(tp);
}
}
@@ -2977,7 +2979,7 @@ static void tcp_init_cwnd_reduction(struct sock *sk)
tp->prior_cwnd = tcp_snd_cwnd(tp);
tp->prr_delivered = 0;
tp->prr_out = 0;
- tp->snd_ssthresh = inet_csk(sk)->icsk_ca_ops->ssthresh(sk);
+ WRITE_ONCE(tp->snd_ssthresh, inet_csk(sk)->icsk_ca_ops->ssthresh(sk));
tcp_ecn_queue_cwr(tp);
}
@@ -3119,7 +3121,7 @@ static void tcp_non_congestion_loss_retransmit(struct sock *sk)
if (icsk->icsk_ca_state != TCP_CA_Loss) {
tp->high_seq = tp->snd_nxt;
- tp->snd_ssthresh = tcp_current_ssthresh(sk);
+ WRITE_ONCE(tp->snd_ssthresh, tcp_current_ssthresh(sk));
tp->prior_ssthresh = 0;
tp->undo_marker = 0;
tcp_set_ca_state(sk, TCP_CA_Loss);
@@ -3912,7 +3914,7 @@ static void tcp_snd_una_update(struct tcp_sock *tp, u32 ack)
sock_owned_by_me((struct sock *)tp);
tp->bytes_acked += delta;
tcp_snd_sne_update(tp, ack);
- tp->snd_una = ack;
+ WRITE_ONCE(tp->snd_una, ack);
}
static void tcp_rcv_sne_update(struct tcp_sock *tp, u32 seq)
@@ -4286,11 +4288,15 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
goto old_ack;
}
- /* If the ack includes data we haven't sent yet, discard
- * this segment (RFC793 Section 3.9).
+ /* If the ack includes data we haven't sent yet, drop the
+ * segment. RFC 793 Section 3.9 and RFC 5961 Section 5.2
+ * require us to send an ACK back in that case.
*/
- if (after(ack, tp->snd_nxt))
+ if (after(ack, tp->snd_nxt)) {
+ if (!(flag & FLAG_NO_CHALLENGE_ACK))
+ tcp_send_challenge_ack(sk, false);
return -SKB_DROP_REASON_TCP_ACK_UNSENT_DATA;
+ }
if (after(ack, prior_snd_una)) {
flag |= FLAG_SND_UNA_ADVANCED;
@@ -6836,7 +6842,7 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack,
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPFASTOPENACTIVE);
/* SYN-data is counted as two separate packets in tcp_ack() */
if (tp->delivered > 1)
- --tp->delivered;
+ WRITE_ONCE(tp->delivered, tp->delivered - 1);
}
tcp_fastopen_add_skb(sk, synack);
@@ -7267,7 +7273,7 @@ tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb)
SKB_DR_SET(reason, NOT_SPECIFIED);
switch (sk->sk_state) {
case TCP_SYN_RECV:
- tp->delivered++; /* SYN-ACK delivery isn't tracked in tcp_ack */
+ WRITE_ONCE(tp->delivered, tp->delivered + 1); /* SYN-ACK delivery isn't tracked in tcp_ack */
if (!tp->srtt_us)
tcp_synack_rtt_meas(sk, req);
@@ -7295,7 +7301,7 @@ tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb)
if (sk->sk_socket)
sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT);
- tp->snd_una = TCP_SKB_CB(skb)->ack_seq;
+ WRITE_ONCE(tp->snd_una, TCP_SKB_CB(skb)->ack_seq);
tp->snd_wnd = ntohs(th->window) << tp->rx_opt.snd_wscale;
tcp_init_wl(tp, TCP_SKB_CB(skb)->seq);
diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c
index 06b1d5d3b6df..dc0c081fc1f3 100644
--- a/net/ipv4/tcp_metrics.c
+++ b/net/ipv4/tcp_metrics.c
@@ -490,13 +490,13 @@ void tcp_init_metrics(struct sock *sk)
val = READ_ONCE(net->ipv4.sysctl_tcp_no_ssthresh_metrics_save) ?
0 : tcp_metric_get(tm, TCP_METRIC_SSTHRESH);
if (val) {
- tp->snd_ssthresh = val;
+ WRITE_ONCE(tp->snd_ssthresh, val);
if (tp->snd_ssthresh > tp->snd_cwnd_clamp)
- tp->snd_ssthresh = tp->snd_cwnd_clamp;
+ WRITE_ONCE(tp->snd_ssthresh, tp->snd_cwnd_clamp);
}
val = tcp_metric_get(tm, TCP_METRIC_REORDERING);
if (val && tp->reordering != val)
- tp->reordering = val;
+ WRITE_ONCE(tp->reordering, val);
crtt = tcp_metric_get(tm, TCP_METRIC_RTT);
rcu_read_unlock();
diff --git a/net/ipv4/tcp_nv.c b/net/ipv4/tcp_nv.c
index a60662f4bdf9..f345897a68df 100644
--- a/net/ipv4/tcp_nv.c
+++ b/net/ipv4/tcp_nv.c
@@ -396,8 +396,8 @@ static void tcpnv_acked(struct sock *sk, const struct ack_sample *sample)
/* We have enough data to determine we are congested */
ca->nv_allow_cwnd_growth = 0;
- tp->snd_ssthresh =
- (nv_ssthresh_factor * max_win) >> 3;
+ WRITE_ONCE(tp->snd_ssthresh,
+ (nv_ssthresh_factor * max_win) >> 3);
if (tcp_snd_cwnd(tp) - max_win > 2) {
/* gap > 2, we do exponential cwnd decrease */
int dec;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 326b58ff1118..a51186b42be9 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -171,7 +171,7 @@ void tcp_cwnd_restart(struct sock *sk, s32 delta)
tcp_ca_event(sk, CA_EVENT_CWND_RESTART);
- tp->snd_ssthresh = tcp_current_ssthresh(sk);
+ WRITE_ONCE(tp->snd_ssthresh, tcp_current_ssthresh(sk));
restart_cwnd = min(restart_cwnd, cwnd);
while ((delta -= inet_csk(sk)->icsk_rto) > 0 && cwnd > restart_cwnd)
@@ -1668,8 +1668,10 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb,
if (skb->len != tcp_header_size) {
tcp_event_data_sent(tp, sk);
- tp->data_segs_out += tcp_skb_pcount(skb);
- tp->bytes_sent += skb->len - tcp_header_size;
+ WRITE_ONCE(tp->data_segs_out,
+ tp->data_segs_out + tcp_skb_pcount(skb));
+ WRITE_ONCE(tp->bytes_sent,
+ tp->bytes_sent + skb->len - tcp_header_size);
}
if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq)
@@ -2124,7 +2126,7 @@ static void tcp_cwnd_application_limited(struct sock *sk)
u32 init_win = tcp_init_cwnd(tp, __sk_dst_get(sk));
u32 win_used = max(tp->snd_cwnd_used, init_win);
if (win_used < tcp_snd_cwnd(tp)) {
- tp->snd_ssthresh = tcp_current_ssthresh(sk);
+ WRITE_ONCE(tp->snd_ssthresh, tcp_current_ssthresh(sk));
tcp_snd_cwnd_set(tp, (tcp_snd_cwnd(tp) + win_used) >> 1);
}
tp->snd_cwnd_used = 0;
@@ -2606,6 +2608,7 @@ static int tcp_clone_payload(struct sock *sk, struct sk_buff *to,
todo = min_t(int, skb_frag_size(fragfrom),
probe_size - len);
len += todo;
+ skb_shinfo(to)->flags |= skb_shinfo(skb)->flags & SKBFL_SHARED_FRAG;
if (lastfrag &&
skb_frag_page(fragfrom) == skb_frag_page(lastfrag) &&
skb_frag_off(fragfrom) == skb_frag_off(lastfrag) +
@@ -2878,30 +2881,6 @@ static bool tcp_small_queue_check(struct sock *sk, const struct sk_buff *skb,
return false;
}
-static void tcp_chrono_set(struct tcp_sock *tp, const enum tcp_chrono new)
-{
- const u32 now = tcp_jiffies32;
- enum tcp_chrono old = tp->chrono_type;
-
- if (old > TCP_CHRONO_UNSPEC)
- tp->chrono_stat[old - 1] += now - tp->chrono_start;
- tp->chrono_start = now;
- tp->chrono_type = new;
-}
-
-void tcp_chrono_start(struct sock *sk, const enum tcp_chrono type)
-{
- struct tcp_sock *tp = tcp_sk(sk);
-
- /* If there are multiple conditions worthy of tracking in a
- * chronograph then the highest priority enum takes precedence
- * over the other conditions. So that if something "more interesting"
- * starts happening, stop the previous chrono and start a new one.
- */
- if (type > tp->chrono_type)
- tcp_chrono_set(tp, type);
-}
-
void tcp_chrono_stop(struct sock *sk, const enum tcp_chrono type)
{
struct tcp_sock *tp = tcp_sk(sk);
@@ -3648,8 +3627,8 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs)
TCP_ADD_STATS(sock_net(sk), TCP_MIB_RETRANSSEGS, segs);
if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)
__NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSYNRETRANS);
- tp->total_retrans += segs;
- tp->bytes_retrans += skb->len;
+ WRITE_ONCE(tp->total_retrans, tp->total_retrans + segs);
+ WRITE_ONCE(tp->bytes_retrans, tp->bytes_retrans + skb->len);
/* make sure skb->data is aligned on arches that require it
* and check if ack-trimming & collapsing extended the headroom
@@ -4159,7 +4138,7 @@ static void tcp_connect_init(struct sock *sk)
tp->snd_wnd = 0;
tcp_init_wl(tp, 0);
tcp_write_queue_purge(sk);
- tp->snd_una = tp->write_seq;
+ WRITE_ONCE(tp->snd_una, tp->write_seq);
tp->snd_sml = tp->write_seq;
tp->snd_up = tp->write_seq;
WRITE_ONCE(tp->snd_nxt, tp->write_seq);
@@ -4652,7 +4631,8 @@ int tcp_rtx_synack(const struct sock *sk, struct request_sock *req)
* However in this case, we are dealing with a passive fastopen
* socket thus we can change total_retrans value.
*/
- tcp_sk_rw(sk)->total_retrans++;
+ WRITE_ONCE(tcp_sk_rw(sk)->total_retrans,
+ tcp_sk_rw(sk)->total_retrans + 1);
}
trace_tcp_retransmit_synack(sk, req);
WRITE_ONCE(req->num_retrans, req->num_retrans + 1);
diff --git a/net/ipv4/tcp_plb.c b/net/ipv4/tcp_plb.c
index 4bcf7eff95e3..b7f9b60d8991 100644
--- a/net/ipv4/tcp_plb.c
+++ b/net/ipv4/tcp_plb.c
@@ -79,7 +79,7 @@ void tcp_plb_check_rehash(struct sock *sk, struct tcp_plb_state *plb)
sk_rethink_txhash(sk);
plb->consec_cong_rounds = 0;
- tcp_sk(sk)->plb_rehash++;
+ WRITE_ONCE(tcp_sk(sk)->plb_rehash, tcp_sk(sk)->plb_rehash + 1);
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPPLBREHASH);
}
EXPORT_SYMBOL_GPL(tcp_plb_check_rehash);
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 5a14a53a3c9e..61631a2dcea7 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -50,7 +50,8 @@ static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk)
u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
{
const struct inet_connection_sock *icsk = inet_csk(sk);
- u32 remaining, user_timeout;
+ u32 user_timeout;
+ s32 remaining;
s32 elapsed;
user_timeout = READ_ONCE(icsk->icsk_user_timeout);
@@ -61,7 +62,7 @@ u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
if (unlikely(elapsed < 0))
elapsed = 0;
remaining = msecs_to_jiffies(user_timeout) - elapsed;
- remaining = max_t(u32, remaining, TCP_TIMEOUT_MIN);
+ remaining = max_t(int, remaining, TCP_TIMEOUT_MIN);
return min_t(u32, remaining, when);
}
@@ -297,7 +298,7 @@ static int tcp_write_timeout(struct sock *sk)
}
if (sk_rethink_txhash(sk)) {
- tp->timeout_rehash++;
+ WRITE_ONCE(tp->timeout_rehash, tp->timeout_rehash + 1);
__NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPTIMEOUTREHASH);
}
diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c
index 786848ad37ea..3ec7308441a7 100644
--- a/net/ipv4/tcp_vegas.c
+++ b/net/ipv4/tcp_vegas.c
@@ -240,7 +240,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked)
*/
tcp_snd_cwnd_set(tp, min(tcp_snd_cwnd(tp),
(u32)target_cwnd + 1));
- tp->snd_ssthresh = tcp_vegas_ssthresh(tp);
+ WRITE_ONCE(tp->snd_ssthresh,
+ tcp_vegas_ssthresh(tp));
} else if (tcp_in_slow_start(tp)) {
/* Slow start. */
@@ -256,8 +257,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked)
* we slow down.
*/
tcp_snd_cwnd_set(tp, tcp_snd_cwnd(tp) - 1);
- tp->snd_ssthresh
- = tcp_vegas_ssthresh(tp);
+ WRITE_ONCE(tp->snd_ssthresh,
+ tcp_vegas_ssthresh(tp));
} else if (diff < alpha) {
/* We don't have enough extra packets
* in the network, so speed up.
@@ -275,7 +276,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked)
else if (tcp_snd_cwnd(tp) > tp->snd_cwnd_clamp)
tcp_snd_cwnd_set(tp, tp->snd_cwnd_clamp);
- tp->snd_ssthresh = tcp_current_ssthresh(sk);
+ WRITE_ONCE(tp->snd_ssthresh, tcp_current_ssthresh(sk));
}
/* Wipe the slate clean for the next RTT. */
diff --git a/net/ipv4/tcp_westwood.c b/net/ipv4/tcp_westwood.c
index c6e97141eef2..b5a42adfd6ca 100644
--- a/net/ipv4/tcp_westwood.c
+++ b/net/ipv4/tcp_westwood.c
@@ -244,11 +244,11 @@ static void tcp_westwood_event(struct sock *sk, enum tcp_ca_event event)
switch (event) {
case CA_EVENT_COMPLETE_CWR:
- tp->snd_ssthresh = tcp_westwood_bw_rttmin(sk);
+ WRITE_ONCE(tp->snd_ssthresh, tcp_westwood_bw_rttmin(sk));
tcp_snd_cwnd_set(tp, tp->snd_ssthresh);
break;
case CA_EVENT_LOSS:
- tp->snd_ssthresh = tcp_westwood_bw_rttmin(sk);
+ WRITE_ONCE(tp->snd_ssthresh, tcp_westwood_bw_rttmin(sk));
/* Update RTT_min when next ack arrives */
w->reset_rtt_min = 1;
break;
diff --git a/net/ipv4/tcp_yeah.c b/net/ipv4/tcp_yeah.c
index 18b07ff5d20e..74a2538e79e0 100644
--- a/net/ipv4/tcp_yeah.c
+++ b/net/ipv4/tcp_yeah.c
@@ -147,7 +147,8 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked)
tcp_snd_cwnd_set(tp, max(tcp_snd_cwnd(tp),
yeah->reno_count));
- tp->snd_ssthresh = tcp_snd_cwnd(tp);
+ WRITE_ONCE(tp->snd_ssthresh,
+ tcp_snd_cwnd(tp));
}
if (yeah->reno_count <= 2)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index cb99a3c27053..2551bfaa2681 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -365,10 +365,10 @@ int udp_v4_get_port(struct sock *sk, unsigned short snum)
return udp_lib_get_port(sk, snum, hash2_nulladdr);
}
-static int compute_score(struct sock *sk, const struct net *net,
- __be32 saddr, __be16 sport,
- __be32 daddr, unsigned short hnum,
- int dif, int sdif)
+static __always_inline int
+compute_score(struct sock *sk, const struct net *net,
+ __be32 saddr, __be16 sport, __be32 daddr,
+ unsigned short hnum, int dif, int sdif)
{
int score;
struct inet_sock *inet;
@@ -508,8 +508,8 @@ static struct sock *udp4_lib_lookup2(const struct net *net,
continue;
/* compute_score is too long of a function to be
- * inlined, and calling it again here yields
- * measurable overhead for some
+ * inlined twice here, and calling it uninlined
+ * here yields measurable overhead for some
* workloads. Work around it by jumping
* backwards to rescore 'result'.
*/
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index d5d23a9296ea..88356cbfb68b 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -1104,7 +1104,6 @@ static int icmpv6_rcv(struct sk_buff *skb)
struct net *net = dev_net_rcu(skb->dev);
struct net_device *dev = icmp6_dev(skb);
struct inet6_dev *idev = __in6_dev_get(dev);
- const struct in6_addr *saddr, *daddr;
struct icmp6hdr *hdr;
u8 type;
@@ -1135,12 +1134,10 @@ static int icmpv6_rcv(struct sk_buff *skb)
__ICMP6_INC_STATS(dev_net_rcu(dev), idev, ICMP6_MIB_INMSGS);
- saddr = &ipv6_hdr(skb)->saddr;
- daddr = &ipv6_hdr(skb)->daddr;
-
if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) {
net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n",
- saddr, daddr);
+ &ipv6_hdr(skb)->saddr,
+ &ipv6_hdr(skb)->daddr);
goto csum_error;
}
@@ -1220,7 +1217,8 @@ static int icmpv6_rcv(struct sk_buff *skb)
break;
net_dbg_ratelimited("icmpv6: msg of unknown type [%pI6c > %pI6c]\n",
- saddr, daddr);
+ &ipv6_hdr(skb)->saddr,
+ &ipv6_hdr(skb)->daddr);
/*
* error of unknown type.
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c
index e119d4f090cc..5be723232df8 100644
--- a/net/ipv6/netfilter/ip6table_nat.c
+++ b/net/ipv6/netfilter/ip6table_nat.c
@@ -81,7 +81,7 @@ static int ip6t_nat_register_lookups(struct net *net)
while (i)
nf_nat_ipv6_unregister_fn(net, &ops[--i]);
- kfree(ops);
+ kfree_rcu(ops, rcu);
return ret;
}
}
@@ -102,7 +102,7 @@ static void ip6t_nat_unregister_lookups(struct net *net)
for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++)
nf_nat_ipv6_unregister_fn(net, &ops[i]);
- kfree(ops);
+ kfree_rcu(ops, rcu);
}
static int ip6table_nat_table_init(struct net *net)
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 010b909275dd..301649a63e8a 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -127,10 +127,11 @@ void udp_v6_rehash(struct sock *sk)
udp_lib_rehash(sk, new_hash, new_hash4);
}
-static int compute_score(struct sock *sk, const struct net *net,
- const struct in6_addr *saddr, __be16 sport,
- const struct in6_addr *daddr, unsigned short hnum,
- int dif, int sdif)
+static __always_inline int
+compute_score(struct sock *sk, const struct net *net,
+ const struct in6_addr *saddr, __be16 sport,
+ const struct in6_addr *daddr, unsigned short hnum,
+ int dif, int sdif)
{
int bound_dev_if, score;
struct inet_sock *inet;
@@ -260,8 +261,8 @@ static struct sock *udp6_lib_lookup2(const struct net *net,
continue;
/* compute_score is too long of a function to be
- * inlined, and calling it again here yields
- * measurable overhead for some
+ * inlined twice here, and calling it uninlined
+ * here yields measurable overhead for some
* workloads. Work around it by jumping
* backwards to rescore 'result'.
*/
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 6a0e2896b54c..53bd98646e33 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -6009,7 +6009,8 @@ ieee80211_determine_our_sta_mode(struct ieee80211_sub_if_data *sdata,
if (is_5ghz &&
!(vht_cap.cap & (IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
- IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
+ IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
+ IEEE80211_VHT_CAP_EXT_NSS_BW_MASK))) {
conn->bw_limit = IEEE80211_CONN_BW_LIMIT_80;
mlme_link_id_dbg(sdata, link_id,
"no VHT 160 MHz capability on 5 GHz, limiting to 80 MHz");
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 1a73d2461c7b..8ef967aa80a0 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -879,6 +879,32 @@ static bool move_skbs_to_msk(struct mptcp_sock *msk, struct sock *ssk)
return moved;
}
+static void mptcp_rcv_rtt_update(struct mptcp_sock *msk,
+ struct mptcp_subflow_context *subflow)
+{
+ const struct tcp_sock *tp = tcp_sk(subflow->tcp_sock);
+ u32 rtt_us = tp->rcv_rtt_est.rtt_us;
+ int id;
+
+ /* Update once per subflow per rcvwnd to avoid touching the msk
+ * too often.
+ */
+ if (!rtt_us || tp->rcv_rtt_est.seq == subflow->prev_rtt_seq)
+ return;
+
+ subflow->prev_rtt_seq = tp->rcv_rtt_est.seq;
+
+ /* Pairs with READ_ONCE() in mptcp_rtt_us_est(). */
+ id = msk->rcv_rtt_est.next_sample;
+ WRITE_ONCE(msk->rcv_rtt_est.samples[id], rtt_us);
+ if (++msk->rcv_rtt_est.next_sample == MPTCP_RTT_SAMPLES)
+ msk->rcv_rtt_est.next_sample = 0;
+
+ /* EWMA among the incoming subflows */
+ msk->scaling_ratio = ((msk->scaling_ratio << 3) - msk->scaling_ratio +
+ tp->scaling_ratio) >> 3;
+}
+
void mptcp_data_ready(struct sock *sk, struct sock *ssk)
{
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
@@ -892,6 +918,7 @@ void mptcp_data_ready(struct sock *sk, struct sock *ssk)
return;
mptcp_data_lock(sk);
+ mptcp_rcv_rtt_update(msk, subflow);
if (!sock_owned_by_user(sk)) {
/* Wake-up the reader only for in-sequence data */
if (move_skbs_to_msk(msk, ssk) && mptcp_epollin_ready(sk))
@@ -2077,7 +2104,6 @@ static void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk)
msk->rcvspace_init = 1;
msk->rcvq_space.copied = 0;
- msk->rcvq_space.rtt_us = 0;
/* initial rcv_space offering made to peer */
msk->rcvq_space.space = min_t(u32, tp->rcv_wnd,
@@ -2088,15 +2114,15 @@ static void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk)
/* receive buffer autotuning. See tcp_rcv_space_adjust for more information.
*
- * Only difference: Use highest rtt estimate of the subflows in use.
+ * Only difference: Use lowest rtt estimate of the subflows in use, see
+ * mptcp_rcv_rtt_update() and mptcp_rtt_us_est().
*/
static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied)
{
struct mptcp_subflow_context *subflow;
struct sock *sk = (struct sock *)msk;
- u8 scaling_ratio = U8_MAX;
- u32 time, advmss = 1;
- u64 rtt_us, mstamp;
+ u32 time, rtt_us;
+ u64 mstamp;
msk_owned_by_me(msk);
@@ -2111,29 +2137,8 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied)
mstamp = mptcp_stamp();
time = tcp_stamp_us_delta(mstamp, READ_ONCE(msk->rcvq_space.time));
- rtt_us = msk->rcvq_space.rtt_us;
- if (rtt_us && time < (rtt_us >> 3))
- return;
-
- rtt_us = 0;
- mptcp_for_each_subflow(msk, subflow) {
- const struct tcp_sock *tp;
- u64 sf_rtt_us;
- u32 sf_advmss;
-
- tp = tcp_sk(mptcp_subflow_tcp_sock(subflow));
-
- sf_rtt_us = READ_ONCE(tp->rcv_rtt_est.rtt_us);
- sf_advmss = READ_ONCE(tp->advmss);
-
- rtt_us = max(sf_rtt_us, rtt_us);
- advmss = max(sf_advmss, advmss);
- scaling_ratio = min(tp->scaling_ratio, scaling_ratio);
- }
-
- msk->rcvq_space.rtt_us = rtt_us;
- msk->scaling_ratio = scaling_ratio;
- if (time < (rtt_us >> 3) || rtt_us == 0)
+ rtt_us = mptcp_rtt_us_est(msk);
+ if (rtt_us == U32_MAX || time < (rtt_us >> 3))
return;
if (msk->rcvq_space.copied <= msk->rcvq_space.space)
@@ -3000,6 +3005,7 @@ static void __mptcp_init_sock(struct sock *sk)
msk->timer_ival = TCP_RTO_MIN;
msk->scaling_ratio = TCP_DEFAULT_SCALING_RATIO;
msk->backlog_len = 0;
+ mptcp_init_rtt_est(msk);
WRITE_ONCE(msk->first, NULL);
inet_csk(sk)->icsk_sync_mss = mptcp_sync_mss;
@@ -3446,6 +3452,7 @@ static int mptcp_disconnect(struct sock *sk, int flags)
msk->bytes_retrans = 0;
msk->rcvspace_init = 0;
msk->fastclosing = 0;
+ mptcp_init_rtt_est(msk);
/* for fallback's sake */
WRITE_ONCE(msk->ack_seq, 0);
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index ec15e503da8b..d19c54761c27 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -268,6 +268,13 @@ struct mptcp_data_frag {
struct page *page;
};
+/* Arbitrary compromise between as low as possible to react timely to subflow
+ * close event and as big as possible to avoid being fouled by biased large
+ * samples due to peer sending data on a different subflow WRT to the incoming
+ * ack.
+ */
+#define MPTCP_RTT_SAMPLES 5
+
/* MPTCP connection sock */
struct mptcp_sock {
/* inet_connection_sock must be the first member */
@@ -340,11 +347,17 @@ struct mptcp_sock {
*/
struct mptcp_pm_data pm;
struct mptcp_sched_ops *sched;
+
+ /* Most recent rtt_us observed by in use incoming subflows. */
+ struct {
+ u32 samples[MPTCP_RTT_SAMPLES];
+ u32 next_sample;
+ } rcv_rtt_est;
+
struct {
int space; /* bytes copied in last measurement window */
int copied; /* bytes copied in this measurement window */
u64 time; /* start time of measurement window */
- u64 rtt_us; /* last maximum rtt of subflows */
} rcvq_space;
u8 scaling_ratio;
bool allow_subflows;
@@ -422,6 +435,27 @@ static inline struct mptcp_data_frag *mptcp_send_head(const struct sock *sk)
return msk->first_pending;
}
+static inline void mptcp_init_rtt_est(struct mptcp_sock *msk)
+{
+ int i;
+
+ for (i = 0; i < MPTCP_RTT_SAMPLES; ++i)
+ msk->rcv_rtt_est.samples[i] = U32_MAX;
+ msk->rcv_rtt_est.next_sample = 0;
+ msk->scaling_ratio = TCP_DEFAULT_SCALING_RATIO;
+}
+
+static inline u32 mptcp_rtt_us_est(const struct mptcp_sock *msk)
+{
+ u32 rtt_us = READ_ONCE(msk->rcv_rtt_est.samples[0]);
+ int i;
+
+ /* Lockless access of collected samples. */
+ for (i = 1; i < MPTCP_RTT_SAMPLES; ++i)
+ rtt_us = min(rtt_us, READ_ONCE(msk->rcv_rtt_est.samples[i]));
+ return rtt_us;
+}
+
static inline struct mptcp_data_frag *mptcp_send_next(struct sock *sk)
{
struct mptcp_sock *msk = mptcp_sk(sk);
@@ -523,6 +557,7 @@ struct mptcp_subflow_context {
u32 map_data_len;
__wsum map_data_csum;
u32 map_csum_len;
+ u32 prev_rtt_seq;
u32 request_mptcp : 1, /* send MP_CAPABLE */
request_join : 1, /* send MP_JOIN */
request_bkup : 1,
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 3601eb86d025..7c570f48ade2 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -102,6 +102,18 @@ __ip_vs_dst_check(struct ip_vs_dest *dest)
return dest_dst;
}
+/* Based on ip_exceeds_mtu(). */
+static bool ip_vs_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
+{
+ if (skb->len <= mtu)
+ return false;
+
+ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu))
+ return false;
+
+ return true;
+}
+
static inline bool
__mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)
{
@@ -111,10 +123,9 @@ __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)
*/
if (IP6CB(skb)->frag_max_size > mtu)
return true; /* largest fragment violate MTU */
- }
- else if (skb->len > mtu && !skb_is_gso(skb)) {
+ } else if (ip_vs_exceeds_mtu(skb, mtu))
return true; /* Packet size violate MTU size */
- }
+
return false;
}
@@ -232,7 +243,7 @@ static inline bool ensure_mtu_is_adequate(struct netns_ipvs *ipvs, int skb_af,
return true;
if (unlikely(ip_hdr(skb)->frag_off & htons(IP_DF) &&
- skb->len > mtu && !skb_is_gso(skb) &&
+ ip_vs_exceeds_mtu(skb, mtu) &&
!ip_vs_iph_icmp(ipvsh))) {
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
htonl(mtu));
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
index 645d2c43ebf7..7e10fa65cbdd 100644
--- a/net/netfilter/nf_conntrack_proto_sctp.c
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -466,9 +466,13 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
if (!ih)
goto out_unlock;
- if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir])
- ct->proto.sctp.init[!dir] = 0;
- ct->proto.sctp.init[dir] = 1;
+ /* Do not record INIT matching peer vtag (stale or retransmitted INIT). */
+ if (old_state == SCTP_CONNTRACK_NONE ||
+ ct->proto.sctp.vtag[!dir] != ih->init_tag) {
+ if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir])
+ ct->proto.sctp.init[!dir] = 0;
+ ct->proto.sctp.init[dir] = 1;
+ }
pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir);
ct->proto.sctp.vtag[!dir] = ih->init_tag;
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 939502ff7c87..81534213f00f 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -181,6 +181,57 @@ static int sip_parse_addr(const struct nf_conn *ct, const char *cp,
return 1;
}
+/* Parse optional port number after IP address.
+ * Returns false on malformed input, true otherwise.
+ * If port is non-NULL, stores parsed port in network byte order.
+ * If no port is present, sets *port to default SIP port.
+ */
+static bool sip_parse_port(const char *dptr, const char **endp,
+ const char *limit, __be16 *port)
+{
+ unsigned int p = 0;
+ int len = 0;
+
+ if (dptr >= limit)
+ return false;
+
+ if (*dptr != ':') {
+ if (port)
+ *port = htons(SIP_PORT);
+ if (endp)
+ *endp = dptr;
+ return true;
+ }
+
+ dptr++; /* skip ':' */
+
+ while (dptr < limit && isdigit(*dptr)) {
+ p = p * 10 + (*dptr - '0');
+ dptr++;
+ len++;
+ if (len > 5) /* max "65535" */
+ return false;
+ }
+
+ if (len == 0)
+ return false;
+
+ /* reached limit while parsing port */
+ if (dptr >= limit)
+ return false;
+
+ if (p < 1024 || p > 65535)
+ return false;
+
+ if (port)
+ *port = htons(p);
+
+ if (endp)
+ *endp = dptr;
+
+ return true;
+}
+
/* skip ip address. returns its length. */
static int epaddr_len(const struct nf_conn *ct, const char *dptr,
const char *limit, int *shift)
@@ -193,11 +244,8 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr,
return 0;
}
- /* Port number */
- if (*dptr == ':') {
- dptr++;
- dptr += digits_len(ct, dptr, limit, shift);
- }
+ if (!sip_parse_port(dptr, &dptr, limit, NULL))
+ return 0;
return dptr - aux;
}
@@ -228,6 +276,51 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr,
return epaddr_len(ct, dptr, limit, shift);
}
+/* simple_strtoul stops after first non-number character.
+ * But as we're not dealing with c-strings, we can't rely on
+ * hitting \r,\n,\0 etc. before moving past end of buffer.
+ *
+ * This is a variant of simple_strtoul, but doesn't require
+ * a c-string.
+ *
+ * If value exceeds UINT_MAX, 0 is returned.
+ */
+static unsigned int sip_strtouint(const char *cp, unsigned int len, char **endp)
+{
+ const unsigned int max = sizeof("4294967295");
+ unsigned int olen = len;
+ const char *s = cp;
+ u64 result = 0;
+
+ if (len > max)
+ len = max;
+
+ while (olen > 0 && isdigit(*s)) {
+ unsigned int value;
+
+ if (len == 0)
+ goto err;
+
+ value = *s - '0';
+ result = result * 10 + value;
+
+ if (result > UINT_MAX)
+ goto err;
+ s++;
+ len--;
+ olen--;
+ }
+
+ if (endp)
+ *endp = (char *)s;
+
+ return result;
+err:
+ if (endp)
+ *endp = (char *)cp;
+ return 0;
+}
+
/* Parse a SIP request line of the form:
*
* Request-Line = Method SP Request-URI SP SIP-Version CRLF
@@ -241,7 +334,6 @@ int ct_sip_parse_request(const struct nf_conn *ct,
{
const char *start = dptr, *limit = dptr + datalen, *end;
unsigned int mlen;
- unsigned int p;
int shift = 0;
/* Skip method and following whitespace */
@@ -267,14 +359,8 @@ int ct_sip_parse_request(const struct nf_conn *ct,
if (!sip_parse_addr(ct, dptr, &end, addr, limit, true))
return -1;
- if (end < limit && *end == ':') {
- end++;
- p = simple_strtoul(end, (char **)&end, 10);
- if (p < 1024 || p > 65535)
- return -1;
- *port = htons(p);
- } else
- *port = htons(SIP_PORT);
+ if (!sip_parse_port(end, &end, limit, port))
+ return -1;
if (end == dptr)
return 0;
@@ -509,7 +595,6 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,
union nf_inet_addr *addr, __be16 *port)
{
const char *c, *limit = dptr + datalen;
- unsigned int p;
int ret;
ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen,
@@ -520,14 +605,8 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,
if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true))
return -1;
- if (*c == ':') {
- c++;
- p = simple_strtoul(c, (char **)&c, 10);
- if (p < 1024 || p > 65535)
- return -1;
- *port = htons(p);
- } else
- *port = htons(SIP_PORT);
+ if (!sip_parse_port(c, &c, limit, port))
+ return -1;
if (dataoff)
*dataoff = c - dptr;
@@ -609,7 +688,7 @@ int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr,
return 0;
start += strlen(name);
- *val = simple_strtoul(start, &end, 0);
+ *val = sip_strtouint(start, limit - start, (char **)&end);
if (start == end)
return -1;
if (matchoff && matchlen) {
@@ -1065,6 +1144,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff,
mediaoff = sdpoff;
for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) {
+ char *end;
+
if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen,
SDP_HDR_MEDIA, SDP_HDR_UNSPEC,
&mediaoff, &medialen) <= 0)
@@ -1080,8 +1161,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff,
mediaoff += t->len;
medialen -= t->len;
- port = simple_strtoul(*dptr + mediaoff, NULL, 10);
- if (port == 0)
+ port = sip_strtouint(*dptr + mediaoff, *datalen - mediaoff, (char **)&end);
+ if (port == 0 || *dptr + mediaoff == end)
continue;
if (port < 1024 || port > 65535) {
nf_ct_helper_log(skb, ct, "wrong port %u", port);
@@ -1255,7 +1336,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
*/
if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES,
&matchoff, &matchlen) > 0)
- expires = simple_strtoul(*dptr + matchoff, NULL, 10);
+ expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL);
ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
SIP_HDR_CONTACT, NULL,
@@ -1286,6 +1367,10 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
goto store_cseq;
}
+ helper = rcu_dereference(nfct_help(ct)->helper);
+ if (!helper)
+ return NF_DROP;
+
exp = nf_ct_expect_alloc(ct);
if (!exp) {
nf_ct_helper_log(skb, ct, "cannot alloc expectation");
@@ -1296,10 +1381,6 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
if (sip_direct_signalling)
saddr = &ct->tuplehash[!dir].tuple.src.u3;
- helper = rcu_dereference(nfct_help(ct)->helper);
- if (!helper)
- return NF_DROP;
-
nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct),
saddr, &daddr, proto, NULL, &port);
exp->timeout.expires = sip_timeout * HZ;
@@ -1359,7 +1440,7 @@ static int process_register_response(struct sk_buff *skb, unsigned int protoff,
if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES,
&matchoff, &matchlen) > 0)
- expires = simple_strtoul(*dptr + matchoff, NULL, 10);
+ expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL);
while (1) {
unsigned int c_expires = expires;
@@ -1419,10 +1500,12 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff,
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
unsigned int matchoff, matchlen, matchend;
unsigned int code, cseq, i;
+ char *end;
if (*datalen < strlen("SIP/2.0 200"))
return NF_ACCEPT;
- code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10);
+ code = sip_strtouint(*dptr + strlen("SIP/2.0 "),
+ *datalen - strlen("SIP/2.0 "), NULL);
if (!code) {
nf_ct_helper_log(skb, ct, "cannot get code");
return NF_DROP;
@@ -1433,8 +1516,8 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff,
nf_ct_helper_log(skb, ct, "cannot parse cseq");
return NF_DROP;
}
- cseq = simple_strtoul(*dptr + matchoff, NULL, 10);
- if (!cseq && *(*dptr + matchoff) != '0') {
+ cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end);
+ if (*dptr + matchoff == end) {
nf_ct_helper_log(skb, ct, "cannot get cseq");
return NF_DROP;
}
@@ -1483,6 +1566,7 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff,
for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
const struct sip_handler *handler;
+ char *end;
handler = &sip_handlers[i];
if (handler->request == NULL)
@@ -1499,8 +1583,8 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff,
nf_ct_helper_log(skb, ct, "cannot parse cseq");
return NF_DROP;
}
- cseq = simple_strtoul(*dptr + matchoff, NULL, 10);
- if (!cseq && *(*dptr + matchoff) != '0') {
+ cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end);
+ if (*dptr + matchoff == end) {
nf_ct_helper_log(skb, ct, "cannot get cseq");
return NF_DROP;
}
@@ -1576,7 +1660,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
&matchoff, &matchlen) <= 0)
break;
- clen = simple_strtoul(dptr + matchoff, (char **)&end, 10);
+ clen = sip_strtouint(dptr + matchoff, datalen - matchoff, (char **)&end);
if (dptr + matchoff == end)
break;
diff --git a/net/netfilter/nf_nat_amanda.c b/net/netfilter/nf_nat_amanda.c
index 98deef6cde69..8f1054920a85 100644
--- a/net/netfilter/nf_nat_amanda.c
+++ b/net/netfilter/nf_nat_amanda.c
@@ -50,7 +50,7 @@ static unsigned int help(struct sk_buff *skb,
return NF_DROP;
}
- sprintf(buffer, "%u", port);
+ snprintf(buffer, sizeof(buffer), "%u", port);
if (!nf_nat_mangle_udp_packet(skb, exp->master, ctinfo,
protoff, matchoff, matchlen,
buffer, strlen(buffer))) {
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
index 3b5434e4ec9c..b30ca94c2bb7 100644
--- a/net/netfilter/nf_nat_core.c
+++ b/net/netfilter/nf_nat_core.c
@@ -1228,9 +1228,11 @@ int nf_nat_register_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops,
ret = nf_register_net_hooks(net, nat_ops, ops_count);
if (ret < 0) {
mutex_unlock(&nf_nat_proto_mutex);
- for (i = 0; i < ops_count; i++)
- kfree(nat_ops[i].priv);
- kfree(nat_ops);
+ for (i = 0; i < ops_count; i++) {
+ priv = nat_ops[i].priv;
+ kfree_rcu(priv, rcu_head);
+ }
+ kfree_rcu(nat_ops, rcu);
return ret;
}
@@ -1294,7 +1296,7 @@ void nf_nat_unregister_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops,
}
nat_proto_net->nat_hook_ops = NULL;
- kfree(nat_ops);
+ kfree_rcu(nat_ops, rcu);
}
unlock:
mutex_unlock(&nf_nat_proto_mutex);
diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c
index cf4aeb299bde..9fbfc6bff0c2 100644
--- a/net/netfilter/nf_nat_sip.c
+++ b/net/netfilter/nf_nat_sip.c
@@ -68,25 +68,27 @@ static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff,
}
static int sip_sprintf_addr(const struct nf_conn *ct, char *buffer,
+ size_t size,
const union nf_inet_addr *addr, bool delim)
{
if (nf_ct_l3num(ct) == NFPROTO_IPV4)
- return sprintf(buffer, "%pI4", &addr->ip);
+ return scnprintf(buffer, size, "%pI4", &addr->ip);
else {
if (delim)
- return sprintf(buffer, "[%pI6c]", &addr->ip6);
+ return scnprintf(buffer, size, "[%pI6c]", &addr->ip6);
else
- return sprintf(buffer, "%pI6c", &addr->ip6);
+ return scnprintf(buffer, size, "%pI6c", &addr->ip6);
}
}
static int sip_sprintf_addr_port(const struct nf_conn *ct, char *buffer,
+ size_t size,
const union nf_inet_addr *addr, u16 port)
{
if (nf_ct_l3num(ct) == NFPROTO_IPV4)
- return sprintf(buffer, "%pI4:%u", &addr->ip, port);
+ return scnprintf(buffer, size, "%pI4:%u", &addr->ip, port);
else
- return sprintf(buffer, "[%pI6c]:%u", &addr->ip6, port);
+ return scnprintf(buffer, size, "[%pI6c]:%u", &addr->ip6, port);
}
static int map_addr(struct sk_buff *skb, unsigned int protoff,
@@ -119,7 +121,7 @@ static int map_addr(struct sk_buff *skb, unsigned int protoff,
if (nf_inet_addr_cmp(&newaddr, addr) && newport == port)
return 1;
- buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, ntohs(newport));
+ buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), &newaddr, ntohs(newport));
return mangle_packet(skb, protoff, dataoff, dptr, datalen,
matchoff, matchlen, buffer, buflen);
}
@@ -212,7 +214,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
&addr, true) > 0 &&
nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) &&
!nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3)) {
- buflen = sip_sprintf_addr(ct, buffer,
+ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer),
&ct->tuplehash[!dir].tuple.dst.u3,
true);
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
@@ -229,7 +231,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
&addr, false) > 0 &&
nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) &&
!nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.src.u3)) {
- buflen = sip_sprintf_addr(ct, buffer,
+ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer),
&ct->tuplehash[!dir].tuple.src.u3,
false);
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
@@ -244,10 +246,11 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen,
"rport=", &poff, &plen,
&n) > 0 &&
+ n >= 1024 && n <= 65535 &&
htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port &&
htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {
__be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
- buflen = sprintf(buffer, "%u", ntohs(p));
+ buflen = scnprintf(buffer, sizeof(buffer), "%u", ntohs(p));
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
poff, plen, buffer, buflen)) {
nf_ct_helper_log(skb, ct, "cannot mangle rport");
@@ -418,7 +421,8 @@ static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff,
if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) ||
exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
- buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port);
+ buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer),
+ &newaddr, port);
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
matchoff, matchlen, buffer, buflen)) {
nf_ct_helper_log(skb, ct, "cannot mangle packet");
@@ -438,8 +442,8 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff,
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+ char buffer[sizeof("4294967295")];
unsigned int matchoff, matchlen;
- char buffer[sizeof("65536")];
int buflen, c_len;
/* Get actual SDP length */
@@ -454,7 +458,7 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff,
&matchoff, &matchlen) <= 0)
return 0;
- buflen = sprintf(buffer, "%u", c_len);
+ buflen = scnprintf(buffer, sizeof(buffer), "%u", c_len);
return mangle_packet(skb, protoff, dataoff, dptr, datalen,
matchoff, matchlen, buffer, buflen);
}
@@ -491,7 +495,7 @@ static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff,
char buffer[INET6_ADDRSTRLEN];
unsigned int buflen;
- buflen = sip_sprintf_addr(ct, buffer, addr, false);
+ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false);
if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen,
sdpoff, type, term, buffer, buflen))
return 0;
@@ -509,7 +513,7 @@ static unsigned int nf_nat_sdp_port(struct sk_buff *skb, unsigned int protoff,
char buffer[sizeof("nnnnn")];
unsigned int buflen;
- buflen = sprintf(buffer, "%u", port);
+ buflen = scnprintf(buffer, sizeof(buffer), "%u", port);
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
matchoff, matchlen, buffer, buflen))
return 0;
@@ -529,7 +533,7 @@ static unsigned int nf_nat_sdp_session(struct sk_buff *skb, unsigned int protoff
unsigned int buflen;
/* Mangle session description owner and contact addresses */
- buflen = sip_sprintf_addr(ct, buffer, addr, false);
+ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false);
if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff,
SDP_HDR_OWNER, SDP_HDR_MEDIA, buffer, buflen))
return 0;
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 8c42247a176c..7927cd48798b 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -374,6 +374,38 @@ static void nft_netdev_hook_free_rcu(struct nft_hook *hook)
call_rcu(&hook->rcu, __nft_netdev_hook_free_rcu);
}
+static void nft_netdev_hook_unlink_free_rcu(struct nft_hook *hook)
+{
+ list_del_rcu(&hook->list);
+ nft_netdev_hook_free_rcu(hook);
+}
+
+static void nft_trans_hook_destroy(struct nft_trans_hook *trans_hook)
+{
+ list_del(&trans_hook->list);
+ kfree(trans_hook);
+}
+
+static void nft_netdev_unregister_trans_hook(struct net *net,
+ const struct nft_table *table,
+ struct list_head *hook_list)
+{
+ struct nft_trans_hook *trans_hook, *next;
+ struct nf_hook_ops *ops;
+ struct nft_hook *hook;
+
+ list_for_each_entry_safe(trans_hook, next, hook_list, list) {
+ hook = trans_hook->hook;
+
+ if (!(table->flags & NFT_TABLE_F_DORMANT)) {
+ list_for_each_entry(ops, &hook->ops_list, list)
+ nf_unregister_net_hook(net, ops);
+ }
+ nft_netdev_hook_unlink_free_rcu(hook);
+ nft_trans_hook_destroy(trans_hook);
+ }
+}
+
static void nft_netdev_unregister_hooks(struct net *net,
struct list_head *hook_list,
bool release_netdev)
@@ -384,10 +416,8 @@ static void nft_netdev_unregister_hooks(struct net *net,
list_for_each_entry_safe(hook, next, hook_list, list) {
list_for_each_entry(ops, &hook->ops_list, list)
nf_unregister_net_hook(net, ops);
- if (release_netdev) {
- list_del(&hook->list);
- nft_netdev_hook_free_rcu(hook);
- }
+ if (release_netdev)
+ nft_netdev_hook_unlink_free_rcu(hook);
}
}
@@ -1994,15 +2024,69 @@ static int nft_nla_put_hook_dev(struct sk_buff *skb, struct nft_hook *hook)
return nla_put_string(skb, attr, hook->ifname);
}
+struct nft_hook_dump_ctx {
+ struct nft_hook *first;
+ int n;
+};
+
+static int nft_dump_basechain_hook_one(struct sk_buff *skb,
+ struct nft_hook *hook,
+ struct nft_hook_dump_ctx *dump_ctx)
+{
+ if (!dump_ctx->first)
+ dump_ctx->first = hook;
+
+ if (nft_nla_put_hook_dev(skb, hook))
+ return -1;
+
+ dump_ctx->n++;
+
+ return 0;
+}
+
+static int nft_dump_basechain_hook_list(struct sk_buff *skb,
+ const struct net *net,
+ const struct list_head *hook_list,
+ struct nft_hook_dump_ctx *dump_ctx)
+{
+ struct nft_hook *hook;
+ int err;
+
+ list_for_each_entry_rcu(hook, hook_list, list,
+ lockdep_commit_lock_is_held(net)) {
+ err = nft_dump_basechain_hook_one(skb, hook, dump_ctx);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int nft_dump_basechain_trans_hook_list(struct sk_buff *skb,
+ const struct list_head *trans_hook_list,
+ struct nft_hook_dump_ctx *dump_ctx)
+{
+ struct nft_trans_hook *trans_hook;
+ int err;
+
+ list_for_each_entry(trans_hook, trans_hook_list, list) {
+ err = nft_dump_basechain_hook_one(skb, trans_hook->hook, dump_ctx);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
static int nft_dump_basechain_hook(struct sk_buff *skb,
const struct net *net, int family,
const struct nft_base_chain *basechain,
- const struct list_head *hook_list)
+ const struct list_head *hook_list,
+ const struct list_head *trans_hook_list)
{
const struct nf_hook_ops *ops = &basechain->ops;
- struct nft_hook *hook, *first = NULL;
+ struct nft_hook_dump_ctx dump_hook_ctx = {};
struct nlattr *nest, *nest_devs;
- int n = 0;
nest = nla_nest_start_noflag(skb, NFTA_CHAIN_HOOK);
if (nest == NULL)
@@ -2017,23 +2101,23 @@ static int nft_dump_basechain_hook(struct sk_buff *skb,
if (!nest_devs)
goto nla_put_failure;
- if (!hook_list)
+ if (!hook_list && !trans_hook_list)
hook_list = &basechain->hook_list;
- list_for_each_entry_rcu(hook, hook_list, list,
- lockdep_commit_lock_is_held(net)) {
- if (!first)
- first = hook;
-
- if (nft_nla_put_hook_dev(skb, hook))
- goto nla_put_failure;
- n++;
+ if (hook_list &&
+ nft_dump_basechain_hook_list(skb, net, hook_list, &dump_hook_ctx)) {
+ goto nla_put_failure;
+ } else if (trans_hook_list &&
+ nft_dump_basechain_trans_hook_list(skb, trans_hook_list,
+ &dump_hook_ctx)) {
+ goto nla_put_failure;
}
+
nla_nest_end(skb, nest_devs);
- if (n == 1 &&
- !hook_is_prefix(first) &&
- nla_put_string(skb, NFTA_HOOK_DEV, first->ifname))
+ if (dump_hook_ctx.n == 1 &&
+ !hook_is_prefix(dump_hook_ctx.first) &&
+ nla_put_string(skb, NFTA_HOOK_DEV, dump_hook_ctx.first->ifname))
goto nla_put_failure;
}
nla_nest_end(skb, nest);
@@ -2047,7 +2131,8 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
u32 portid, u32 seq, int event, u32 flags,
int family, const struct nft_table *table,
const struct nft_chain *chain,
- const struct list_head *hook_list)
+ const struct list_head *hook_list,
+ const struct list_head *trans_hook_list)
{
struct nlmsghdr *nlh;
@@ -2063,7 +2148,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
NFTA_CHAIN_PAD))
goto nla_put_failure;
- if (!hook_list &&
+ if (!hook_list && !trans_hook_list &&
(event == NFT_MSG_DELCHAIN ||
event == NFT_MSG_DESTROYCHAIN)) {
nlmsg_end(skb, nlh);
@@ -2074,7 +2159,8 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
const struct nft_base_chain *basechain = nft_base_chain(chain);
struct nft_stats __percpu *stats;
- if (nft_dump_basechain_hook(skb, net, family, basechain, hook_list))
+ if (nft_dump_basechain_hook(skb, net, family, basechain,
+ hook_list, trans_hook_list))
goto nla_put_failure;
if (nla_put_be32(skb, NFTA_CHAIN_POLICY,
@@ -2110,7 +2196,8 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
}
static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event,
- const struct list_head *hook_list)
+ const struct list_head *hook_list,
+ const struct list_head *trans_hook_list)
{
struct nftables_pernet *nft_net;
struct sk_buff *skb;
@@ -2130,7 +2217,7 @@ static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event,
err = nf_tables_fill_chain_info(skb, ctx->net, ctx->portid, ctx->seq,
event, flags, ctx->family, ctx->table,
- ctx->chain, hook_list);
+ ctx->chain, hook_list, trans_hook_list);
if (err < 0) {
kfree_skb(skb);
goto err;
@@ -2176,7 +2263,7 @@ static int nf_tables_dump_chains(struct sk_buff *skb,
NFT_MSG_NEWCHAIN,
NLM_F_MULTI,
table->family, table,
- chain, NULL) < 0)
+ chain, NULL, NULL) < 0)
goto done;
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
@@ -2230,7 +2317,7 @@ static int nf_tables_getchain(struct sk_buff *skb, const struct nfnl_info *info,
err = nf_tables_fill_chain_info(skb2, net, NETLINK_CB(skb).portid,
info->nlh->nlmsg_seq, NFT_MSG_NEWCHAIN,
- 0, family, table, chain, NULL);
+ 0, family, table, chain, NULL, NULL);
if (err < 0)
goto err_fill_chain_info;
@@ -2323,10 +2410,8 @@ void nf_tables_chain_destroy(struct nft_chain *chain)
if (nft_base_chain_netdev(table->family, basechain->ops.hooknum)) {
list_for_each_entry_safe(hook, next,
- &basechain->hook_list, list) {
- list_del_rcu(&hook->list);
- nft_netdev_hook_free_rcu(hook);
- }
+ &basechain->hook_list, list)
+ nft_netdev_hook_unlink_free_rcu(hook);
}
module_put(basechain->type->owner);
if (rcu_access_pointer(basechain->stats)) {
@@ -2395,8 +2480,12 @@ static struct nft_hook *nft_hook_list_find(struct list_head *hook_list,
list_for_each_entry(hook, hook_list, list) {
if (!strncmp(hook->ifname, this->ifname,
- min(hook->ifnamelen, this->ifnamelen)))
+ min(hook->ifnamelen, this->ifnamelen))) {
+ if (hook->flags & NFT_HOOK_REMOVE)
+ continue;
+
return hook;
+ }
}
return NULL;
@@ -3026,6 +3115,7 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
list_for_each_entry(ops, &h->ops_list, list)
nf_unregister_net_hook(ctx->net, ops);
}
+ /* hook.list is on stack, no need for list_del_rcu() */
list_del(&h->list);
nft_netdev_hook_free_rcu(h);
}
@@ -3154,6 +3244,32 @@ static int nf_tables_newchain(struct sk_buff *skb, const struct nfnl_info *info,
return nf_tables_addchain(&ctx, family, policy, flags, extack);
}
+static int nft_trans_delhook(struct nft_hook *hook,
+ struct list_head *del_list)
+{
+ struct nft_trans_hook *trans_hook;
+
+ trans_hook = kmalloc_obj(*trans_hook, GFP_KERNEL);
+ if (!trans_hook)
+ return -ENOMEM;
+
+ trans_hook->hook = hook;
+ list_add_tail(&trans_hook->list, del_list);
+ hook->flags |= NFT_HOOK_REMOVE;
+
+ return 0;
+}
+
+static void nft_trans_delhook_abort(struct list_head *del_list)
+{
+ struct nft_trans_hook *trans_hook, *next;
+
+ list_for_each_entry_safe(trans_hook, next, del_list, list) {
+ trans_hook->hook->flags &= ~NFT_HOOK_REMOVE;
+ nft_trans_hook_destroy(trans_hook);
+ }
+}
+
static int nft_delchain_hook(struct nft_ctx *ctx,
struct nft_base_chain *basechain,
struct netlink_ext_ack *extack)
@@ -3180,7 +3296,10 @@ static int nft_delchain_hook(struct nft_ctx *ctx,
err = -ENOENT;
goto err_chain_del_hook;
}
- list_move(&hook->list, &chain_del_list);
+ if (nft_trans_delhook(hook, &chain_del_list) < 0) {
+ err = -ENOMEM;
+ goto err_chain_del_hook;
+ }
}
trans = nft_trans_alloc_chain(ctx, NFT_MSG_DELCHAIN);
@@ -3200,7 +3319,7 @@ static int nft_delchain_hook(struct nft_ctx *ctx,
return 0;
err_chain_del_hook:
- list_splice(&chain_del_list, &basechain->hook_list);
+ nft_trans_delhook_abort(&chain_del_list);
nft_chain_release_hook(&chain_hook);
return err;
@@ -8903,10 +9022,8 @@ static void __nft_unregister_flowtable_net_hooks(struct net *net,
list_for_each_entry_safe(hook, next, hook_list, list) {
list_for_each_entry(ops, &hook->ops_list, list)
nft_unregister_flowtable_ops(net, flowtable, ops);
- if (release_netdev) {
- list_del(&hook->list);
- nft_netdev_hook_free_rcu(hook);
- }
+ if (release_netdev)
+ nft_netdev_hook_unlink_free_rcu(hook);
}
}
@@ -8977,8 +9094,7 @@ static int nft_register_flowtable_net_hooks(struct net *net,
nft_unregister_flowtable_ops(net, flowtable, ops);
}
- list_del_rcu(&hook->list);
- nft_netdev_hook_free_rcu(hook);
+ nft_netdev_hook_unlink_free_rcu(hook);
}
return err;
@@ -8988,9 +9104,25 @@ static void nft_hooks_destroy(struct list_head *hook_list)
{
struct nft_hook *hook, *next;
- list_for_each_entry_safe(hook, next, hook_list, list) {
- list_del_rcu(&hook->list);
- nft_netdev_hook_free_rcu(hook);
+ list_for_each_entry_safe(hook, next, hook_list, list)
+ nft_netdev_hook_unlink_free_rcu(hook);
+}
+
+static void nft_flowtable_unregister_trans_hook(struct net *net,
+ struct nft_flowtable *flowtable,
+ struct list_head *hook_list)
+{
+ struct nft_trans_hook *trans_hook, *next;
+ struct nf_hook_ops *ops;
+ struct nft_hook *hook;
+
+ list_for_each_entry_safe(trans_hook, next, hook_list, list) {
+ hook = trans_hook->hook;
+ list_for_each_entry(ops, &hook->ops_list, list)
+ nft_unregister_flowtable_ops(net, flowtable, ops);
+
+ nft_netdev_hook_unlink_free_rcu(hook);
+ nft_trans_hook_destroy(trans_hook);
}
}
@@ -9079,8 +9211,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
nft_unregister_flowtable_ops(ctx->net,
flowtable, ops);
}
- list_del_rcu(&hook->list);
- nft_netdev_hook_free_rcu(hook);
+ nft_netdev_hook_unlink_free_rcu(hook);
}
return err;
@@ -9253,7 +9384,10 @@ static int nft_delflowtable_hook(struct nft_ctx *ctx,
err = -ENOENT;
goto err_flowtable_del_hook;
}
- list_move(&hook->list, &flowtable_del_list);
+ if (nft_trans_delhook(hook, &flowtable_del_list) < 0) {
+ err = -ENOMEM;
+ goto err_flowtable_del_hook;
+ }
}
trans = nft_trans_alloc(ctx, NFT_MSG_DELFLOWTABLE,
@@ -9274,7 +9408,7 @@ static int nft_delflowtable_hook(struct nft_ctx *ctx,
return 0;
err_flowtable_del_hook:
- list_splice(&flowtable_del_list, &flowtable->hook_list);
+ nft_trans_delhook_abort(&flowtable_del_list);
nft_flowtable_hook_release(&flowtable_hook);
return err;
@@ -9339,8 +9473,10 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
u32 portid, u32 seq, int event,
u32 flags, int family,
struct nft_flowtable *flowtable,
- struct list_head *hook_list)
+ struct list_head *hook_list,
+ struct list_head *trans_hook_list)
{
+ struct nft_trans_hook *trans_hook;
struct nlattr *nest, *nest_devs;
struct nft_hook *hook;
struct nlmsghdr *nlh;
@@ -9357,7 +9493,7 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
NFTA_FLOWTABLE_PAD))
goto nla_put_failure;
- if (!hook_list &&
+ if (!hook_list && !trans_hook_list &&
(event == NFT_MSG_DELFLOWTABLE ||
event == NFT_MSG_DESTROYFLOWTABLE)) {
nlmsg_end(skb, nlh);
@@ -9379,13 +9515,20 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
if (!nest_devs)
goto nla_put_failure;
- if (!hook_list)
+ if (!hook_list && !trans_hook_list)
hook_list = &flowtable->hook_list;
- list_for_each_entry_rcu(hook, hook_list, list,
- lockdep_commit_lock_is_held(net)) {
- if (nft_nla_put_hook_dev(skb, hook))
- goto nla_put_failure;
+ if (hook_list) {
+ list_for_each_entry_rcu(hook, hook_list, list,
+ lockdep_commit_lock_is_held(net)) {
+ if (nft_nla_put_hook_dev(skb, hook))
+ goto nla_put_failure;
+ }
+ } else if (trans_hook_list) {
+ list_for_each_entry(trans_hook, trans_hook_list, list) {
+ if (nft_nla_put_hook_dev(skb, trans_hook->hook))
+ goto nla_put_failure;
+ }
}
nla_nest_end(skb, nest_devs);
nla_nest_end(skb, nest);
@@ -9439,7 +9582,7 @@ static int nf_tables_dump_flowtable(struct sk_buff *skb,
NFT_MSG_NEWFLOWTABLE,
NLM_F_MULTI | NLM_F_APPEND,
table->family,
- flowtable, NULL) < 0)
+ flowtable, NULL, NULL) < 0)
goto done;
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
@@ -9539,7 +9682,7 @@ static int nf_tables_getflowtable(struct sk_buff *skb,
err = nf_tables_fill_flowtable_info(skb2, net, NETLINK_CB(skb).portid,
info->nlh->nlmsg_seq,
NFT_MSG_NEWFLOWTABLE, 0, family,
- flowtable, NULL);
+ flowtable, NULL, NULL);
if (err < 0)
goto err_fill_flowtable_info;
@@ -9552,7 +9695,9 @@ static int nf_tables_getflowtable(struct sk_buff *skb,
static void nf_tables_flowtable_notify(struct nft_ctx *ctx,
struct nft_flowtable *flowtable,
- struct list_head *hook_list, int event)
+ struct list_head *hook_list,
+ struct list_head *trans_hook_list,
+ int event)
{
struct nftables_pernet *nft_net = nft_pernet(ctx->net);
struct sk_buff *skb;
@@ -9572,7 +9717,8 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx,
err = nf_tables_fill_flowtable_info(skb, ctx->net, ctx->portid,
ctx->seq, event, flags,
- ctx->family, flowtable, hook_list);
+ ctx->family, flowtable,
+ hook_list, trans_hook_list);
if (err < 0) {
kfree_skb(skb);
goto err;
@@ -9586,13 +9732,8 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx,
static void nf_tables_flowtable_destroy(struct nft_flowtable *flowtable)
{
- struct nft_hook *hook, *next;
-
flowtable->data.type->free(&flowtable->data);
- list_for_each_entry_safe(hook, next, &flowtable->hook_list, list) {
- list_del_rcu(&hook->list);
- nft_netdev_hook_free_rcu(hook);
- }
+ nft_hooks_destroy(&flowtable->hook_list);
kfree(flowtable->name);
module_put(flowtable->data.type->owner);
kfree(flowtable);
@@ -10111,9 +10252,7 @@ static void nft_commit_release(struct nft_trans *trans)
break;
case NFT_MSG_DELCHAIN:
case NFT_MSG_DESTROYCHAIN:
- if (nft_trans_chain_update(trans))
- nft_hooks_destroy(&nft_trans_chain_hooks(trans));
- else
+ if (!nft_trans_chain_update(trans))
nf_tables_chain_destroy(nft_trans_chain(trans));
break;
case NFT_MSG_DELRULE:
@@ -10134,9 +10273,7 @@ static void nft_commit_release(struct nft_trans *trans)
break;
case NFT_MSG_DELFLOWTABLE:
case NFT_MSG_DESTROYFLOWTABLE:
- if (nft_trans_flowtable_update(trans))
- nft_hooks_destroy(&nft_trans_flowtable_hooks(trans));
- else
+ if (!nft_trans_flowtable_update(trans))
nf_tables_flowtable_destroy(nft_trans_flowtable(trans));
break;
}
@@ -10911,31 +11048,28 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
if (nft_trans_chain_update(trans)) {
nft_chain_commit_update(nft_trans_container_chain(trans));
nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN,
- &nft_trans_chain_hooks(trans));
- list_splice(&nft_trans_chain_hooks(trans),
- &nft_trans_basechain(trans)->hook_list);
+ &nft_trans_chain_hooks(trans), NULL);
+ list_splice_rcu(&nft_trans_chain_hooks(trans),
+ &nft_trans_basechain(trans)->hook_list);
/* trans destroyed after rcu grace period */
} else {
nft_chain_commit_drop_policy(nft_trans_container_chain(trans));
nft_clear(net, nft_trans_chain(trans));
- nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN, NULL);
+ nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN, NULL, NULL);
nft_trans_destroy(trans);
}
break;
case NFT_MSG_DELCHAIN:
case NFT_MSG_DESTROYCHAIN:
if (nft_trans_chain_update(trans)) {
- nf_tables_chain_notify(&ctx, NFT_MSG_DELCHAIN,
+ nf_tables_chain_notify(&ctx, NFT_MSG_DELCHAIN, NULL,
&nft_trans_chain_hooks(trans));
- if (!(table->flags & NFT_TABLE_F_DORMANT)) {
- nft_netdev_unregister_hooks(net,
- &nft_trans_chain_hooks(trans),
- true);
- }
+ nft_netdev_unregister_trans_hook(net, table,
+ &nft_trans_chain_hooks(trans));
} else {
nft_chain_del(nft_trans_chain(trans));
nf_tables_chain_notify(&ctx, NFT_MSG_DELCHAIN,
- NULL);
+ NULL, NULL);
nf_tables_unregister_hook(ctx.net, ctx.table,
nft_trans_chain(trans));
}
@@ -11041,14 +11175,16 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
nf_tables_flowtable_notify(&ctx,
nft_trans_flowtable(trans),
&nft_trans_flowtable_hooks(trans),
+ NULL,
NFT_MSG_NEWFLOWTABLE);
- list_splice(&nft_trans_flowtable_hooks(trans),
- &nft_trans_flowtable(trans)->hook_list);
+ list_splice_rcu(&nft_trans_flowtable_hooks(trans),
+ &nft_trans_flowtable(trans)->hook_list);
} else {
nft_clear(net, nft_trans_flowtable(trans));
nf_tables_flowtable_notify(&ctx,
nft_trans_flowtable(trans),
NULL,
+ NULL,
NFT_MSG_NEWFLOWTABLE);
}
nft_trans_destroy(trans);
@@ -11058,16 +11194,18 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
if (nft_trans_flowtable_update(trans)) {
nf_tables_flowtable_notify(&ctx,
nft_trans_flowtable(trans),
+ NULL,
&nft_trans_flowtable_hooks(trans),
trans->msg_type);
- nft_unregister_flowtable_net_hooks(net,
- nft_trans_flowtable(trans),
- &nft_trans_flowtable_hooks(trans));
+ nft_flowtable_unregister_trans_hook(net,
+ nft_trans_flowtable(trans),
+ &nft_trans_flowtable_hooks(trans));
} else {
list_del_rcu(&nft_trans_flowtable(trans)->list);
nf_tables_flowtable_notify(&ctx,
nft_trans_flowtable(trans),
NULL,
+ NULL,
trans->msg_type);
nft_unregister_flowtable_net_hooks(net,
nft_trans_flowtable(trans),
@@ -11231,8 +11369,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
case NFT_MSG_DELCHAIN:
case NFT_MSG_DESTROYCHAIN:
if (nft_trans_chain_update(trans)) {
- list_splice(&nft_trans_chain_hooks(trans),
- &nft_trans_basechain(trans)->hook_list);
+ nft_trans_delhook_abort(&nft_trans_chain_hooks(trans));
} else {
nft_use_inc_restore(&table->use);
nft_clear(trans->net, nft_trans_chain(trans));
@@ -11346,8 +11483,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
case NFT_MSG_DELFLOWTABLE:
case NFT_MSG_DESTROYFLOWTABLE:
if (nft_trans_flowtable_update(trans)) {
- list_splice(&nft_trans_flowtable_hooks(trans),
- &nft_trans_flowtable(trans)->hook_list);
+ nft_trans_delhook_abort(&nft_trans_flowtable_hooks(trans));
} else {
nft_use_inc_restore(&table->use);
nft_clear(trans->net, nft_trans_flowtable(trans));
diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c
index 45d9ad231a92..426b85fca8f7 100644
--- a/net/netfilter/nfnetlink_osf.c
+++ b/net/netfilter/nfnetlink_osf.c
@@ -31,26 +31,18 @@ EXPORT_SYMBOL_GPL(nf_osf_fingers);
static inline int nf_osf_ttl(const struct sk_buff *skb,
int ttl_check, unsigned char f_ttl)
{
- struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
const struct iphdr *ip = ip_hdr(skb);
- const struct in_ifaddr *ifa;
- int ret = 0;
- if (ttl_check == NF_OSF_TTL_TRUE)
+ switch (ttl_check) {
+ case NF_OSF_TTL_TRUE:
return ip->ttl == f_ttl;
- if (ttl_check == NF_OSF_TTL_NOCHECK)
- return 1;
- else if (ip->ttl <= f_ttl)
+ break;
+ case NF_OSF_TTL_NOCHECK:
return 1;
-
- in_dev_for_each_ifa_rcu(ifa, in_dev) {
- if (inet_ifa_match(ip->saddr, ifa)) {
- ret = (ip->ttl == f_ttl);
- break;
- }
+ case NF_OSF_TTL_LESS:
+ default:
+ return ip->ttl <= f_ttl;
}
-
- return ret;
}
struct nf_osf_hdr_ctx {
@@ -64,9 +56,9 @@ struct nf_osf_hdr_ctx {
static bool nf_osf_match_one(const struct sk_buff *skb,
const struct nf_osf_user_finger *f,
int ttl_check,
- struct nf_osf_hdr_ctx *ctx)
+ const struct nf_osf_hdr_ctx *ctx)
{
- const __u8 *optpinit = ctx->optp;
+ const __u8 *optp = ctx->optp;
unsigned int check_WSS = 0;
int fmatch = FMATCH_WRONG;
int foptsize, optnum;
@@ -95,17 +87,17 @@ static bool nf_osf_match_one(const struct sk_buff *skb,
check_WSS = f->wss.wc;
for (optnum = 0; optnum < f->opt_num; ++optnum) {
- if (f->opt[optnum].kind == *ctx->optp) {
+ if (f->opt[optnum].kind == *optp) {
__u32 len = f->opt[optnum].length;
- const __u8 *optend = ctx->optp + len;
+ const __u8 *optend = optp + len;
fmatch = FMATCH_OK;
- switch (*ctx->optp) {
+ switch (*optp) {
case OSFOPT_MSS:
- mss = ctx->optp[3];
+ mss = optp[3];
mss <<= 8;
- mss |= ctx->optp[2];
+ mss |= optp[2];
mss = ntohs((__force __be16)mss);
break;
@@ -113,7 +105,7 @@ static bool nf_osf_match_one(const struct sk_buff *skb,
break;
}
- ctx->optp = optend;
+ optp = optend;
} else
fmatch = FMATCH_OPT_WRONG;
@@ -156,9 +148,6 @@ static bool nf_osf_match_one(const struct sk_buff *skb,
}
}
- if (fmatch != FMATCH_OK)
- ctx->optp = optpinit;
-
return fmatch == FMATCH_OK;
}
@@ -320,6 +309,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb,
if (f->opt_num > ARRAY_SIZE(f->opt))
return -EINVAL;
+ if (f->wss.wc >= OSF_WSS_MAX ||
+ (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0))
+ return -EINVAL;
+
for (i = 0; i < f->opt_num; i++) {
if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN)
return -EINVAL;
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
index 04c74ccf9b84..272ce1811807 100644
--- a/net/netfilter/nft_ct.c
+++ b/net/netfilter/nft_ct.c
@@ -1381,6 +1381,8 @@ static void nft_ct_expect_obj_eval(struct nft_object *obj,
if (nf_ct_expect_related(exp, 0) != 0)
regs->verdict.code = NF_DROP;
+
+ nf_ct_expect_put(exp);
}
static const struct nla_policy nft_ct_expect_policy[NFTA_CT_EXPECT_MAX + 1] = {
diff --git a/net/netfilter/nft_fwd_netdev.c b/net/netfilter/nft_fwd_netdev.c
index 152a9fb4d23a..256e832f1bb9 100644
--- a/net/netfilter/nft_fwd_netdev.c
+++ b/net/netfilter/nft_fwd_netdev.c
@@ -116,6 +116,11 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr,
goto out;
}
iph = ip_hdr(skb);
+ if (iph->ttl <= 1) {
+ verdict = NF_DROP;
+ goto out;
+ }
+
ip_decrease_ttl(iph);
neigh_table = NEIGH_ARP_TABLE;
break;
@@ -132,6 +137,11 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr,
goto out;
}
ip6h = ipv6_hdr(skb);
+ if (ip6h->hop_limit <= 1) {
+ verdict = NF_DROP;
+ goto out;
+ }
+
ip6h->hop_limit--;
neigh_table = NEIGH_ND_TABLE;
break;
diff --git a/net/netfilter/nft_osf.c b/net/netfilter/nft_osf.c
index 1c0b493ef0a9..bdc2f6c90e2f 100644
--- a/net/netfilter/nft_osf.c
+++ b/net/netfilter/nft_osf.c
@@ -28,6 +28,11 @@ static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs,
struct nf_osf_data data;
struct tcphdr _tcph;
+ if (nft_pf(pkt) != NFPROTO_IPV4) {
+ regs->verdict.code = NFT_BREAK;
+ return;
+ }
+
if (pkt->tprot != IPPROTO_TCP) {
regs->verdict.code = NFT_BREAK;
return;
@@ -114,7 +119,6 @@ static int nft_osf_validate(const struct nft_ctx *ctx,
switch (ctx->family) {
case NFPROTO_IPV4:
- case NFPROTO_IPV6:
case NFPROTO_INET:
hooks = (1 << NF_INET_LOCAL_IN) |
(1 << NF_INET_PRE_ROUTING) |
diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c
index 81649da57ba5..bd2354760895 100644
--- a/net/netfilter/xt_mac.c
+++ b/net/netfilter/xt_mac.c
@@ -38,25 +38,37 @@ static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par)
return ret;
}
-static struct xt_match mac_mt_reg __read_mostly = {
- .name = "mac",
- .revision = 0,
- .family = NFPROTO_UNSPEC,
- .match = mac_mt,
- .matchsize = sizeof(struct xt_mac_info),
- .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN) |
- (1 << NF_INET_FORWARD),
- .me = THIS_MODULE,
+static struct xt_match mac_mt_reg[] __read_mostly = {
+ {
+ .name = "mac",
+ .family = NFPROTO_IPV4,
+ .match = mac_mt,
+ .matchsize = sizeof(struct xt_mac_info),
+ .hooks = (1 << NF_INET_PRE_ROUTING) |
+ (1 << NF_INET_LOCAL_IN) |
+ (1 << NF_INET_FORWARD),
+ .me = THIS_MODULE,
+ },
+ {
+ .name = "mac",
+ .family = NFPROTO_IPV6,
+ .match = mac_mt,
+ .matchsize = sizeof(struct xt_mac_info),
+ .hooks = (1 << NF_INET_PRE_ROUTING) |
+ (1 << NF_INET_LOCAL_IN) |
+ (1 << NF_INET_FORWARD),
+ .me = THIS_MODULE,
+ },
};
static int __init mac_mt_init(void)
{
- return xt_register_match(&mac_mt_reg);
+ return xt_register_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg));
}
static void __exit mac_mt_exit(void)
{
- xt_unregister_match(&mac_mt_reg);
+ xt_unregister_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg));
}
module_init(mac_mt_init);
diff --git a/net/netfilter/xt_owner.c b/net/netfilter/xt_owner.c
index 50332888c8d2..7be2fe22b067 100644
--- a/net/netfilter/xt_owner.c
+++ b/net/netfilter/xt_owner.c
@@ -127,26 +127,39 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par)
return true;
}
-static struct xt_match owner_mt_reg __read_mostly = {
- .name = "owner",
- .revision = 1,
- .family = NFPROTO_UNSPEC,
- .checkentry = owner_check,
- .match = owner_mt,
- .matchsize = sizeof(struct xt_owner_match_info),
- .hooks = (1 << NF_INET_LOCAL_OUT) |
- (1 << NF_INET_POST_ROUTING),
- .me = THIS_MODULE,
+static struct xt_match owner_mt_reg[] __read_mostly = {
+ {
+ .name = "owner",
+ .revision = 1,
+ .family = NFPROTO_IPV4,
+ .checkentry = owner_check,
+ .match = owner_mt,
+ .matchsize = sizeof(struct xt_owner_match_info),
+ .hooks = (1 << NF_INET_LOCAL_OUT) |
+ (1 << NF_INET_POST_ROUTING),
+ .me = THIS_MODULE,
+ },
+ {
+ .name = "owner",
+ .revision = 1,
+ .family = NFPROTO_IPV6,
+ .checkentry = owner_check,
+ .match = owner_mt,
+ .matchsize = sizeof(struct xt_owner_match_info),
+ .hooks = (1 << NF_INET_LOCAL_OUT) |
+ (1 << NF_INET_POST_ROUTING),
+ .me = THIS_MODULE,
+ }
};
static int __init owner_mt_init(void)
{
- return xt_register_match(&owner_mt_reg);
+ return xt_register_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg));
}
static void __exit owner_mt_exit(void)
{
- xt_unregister_match(&owner_mt_reg);
+ xt_unregister_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg));
}
module_init(owner_mt_init);
diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c
index 343e65f377d4..130842c35c6f 100644
--- a/net/netfilter/xt_physdev.c
+++ b/net/netfilter/xt_physdev.c
@@ -115,24 +115,33 @@ static int physdev_mt_check(const struct xt_mtchk_param *par)
return 0;
}
-static struct xt_match physdev_mt_reg __read_mostly = {
- .name = "physdev",
- .revision = 0,
- .family = NFPROTO_UNSPEC,
- .checkentry = physdev_mt_check,
- .match = physdev_mt,
- .matchsize = sizeof(struct xt_physdev_info),
- .me = THIS_MODULE,
+static struct xt_match physdev_mt_reg[] __read_mostly = {
+ {
+ .name = "physdev",
+ .family = NFPROTO_IPV4,
+ .checkentry = physdev_mt_check,
+ .match = physdev_mt,
+ .matchsize = sizeof(struct xt_physdev_info),
+ .me = THIS_MODULE,
+ },
+ {
+ .name = "physdev",
+ .family = NFPROTO_IPV6,
+ .checkentry = physdev_mt_check,
+ .match = physdev_mt,
+ .matchsize = sizeof(struct xt_physdev_info),
+ .me = THIS_MODULE,
+ },
};
static int __init physdev_mt_init(void)
{
- return xt_register_match(&physdev_mt_reg);
+ return xt_register_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg));
}
static void __exit physdev_mt_exit(void)
{
- xt_unregister_match(&physdev_mt_reg);
+ xt_unregister_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg));
}
module_init(physdev_mt_init);
diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c
index cb6e8279010a..b5fa65558318 100644
--- a/net/netfilter/xt_policy.c
+++ b/net/netfilter/xt_policy.c
@@ -63,7 +63,7 @@ match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info,
return 0;
for (i = sp->len - 1; i >= 0; i--) {
- pos = strict ? i - sp->len + 1 : 0;
+ pos = strict ? sp->len - i - 1 : 0;
if (pos >= info->len)
return 0;
e = &info->pol[pos];
diff --git a/net/netfilter/xt_realm.c b/net/netfilter/xt_realm.c
index 6df485f4403d..61b2f1e58d15 100644
--- a/net/netfilter/xt_realm.c
+++ b/net/netfilter/xt_realm.c
@@ -33,7 +33,7 @@ static struct xt_match realm_mt_reg __read_mostly = {
.matchsize = sizeof(struct xt_realm_info),
.hooks = (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_FORWARD) |
(1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_LOCAL_IN),
- .family = NFPROTO_UNSPEC,
+ .family = NFPROTO_IPV4,
.me = THIS_MODULE
};
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
index 76e01f292aaf..811e53bee408 100644
--- a/net/netfilter/xt_socket.c
+++ b/net/netfilter/xt_socket.c
@@ -168,52 +168,41 @@ static int socket_mt_enable_defrag(struct net *net, int family)
static int socket_mt_v1_check(const struct xt_mtchk_param *par)
{
const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;
- int err;
-
- err = socket_mt_enable_defrag(par->net, par->family);
- if (err)
- return err;
if (info->flags & ~XT_SOCKET_FLAGS_V1) {
pr_info_ratelimited("unknown flags 0x%x\n",
info->flags & ~XT_SOCKET_FLAGS_V1);
return -EINVAL;
}
- return 0;
+
+ return socket_mt_enable_defrag(par->net, par->family);
}
static int socket_mt_v2_check(const struct xt_mtchk_param *par)
{
const struct xt_socket_mtinfo2 *info = (struct xt_socket_mtinfo2 *) par->matchinfo;
- int err;
-
- err = socket_mt_enable_defrag(par->net, par->family);
- if (err)
- return err;
if (info->flags & ~XT_SOCKET_FLAGS_V2) {
pr_info_ratelimited("unknown flags 0x%x\n",
info->flags & ~XT_SOCKET_FLAGS_V2);
return -EINVAL;
}
- return 0;
+
+ return socket_mt_enable_defrag(par->net, par->family);
}
static int socket_mt_v3_check(const struct xt_mtchk_param *par)
{
const struct xt_socket_mtinfo3 *info =
(struct xt_socket_mtinfo3 *)par->matchinfo;
- int err;
- err = socket_mt_enable_defrag(par->net, par->family);
- if (err)
- return err;
if (info->flags & ~XT_SOCKET_FLAGS_V3) {
pr_info_ratelimited("unknown flags 0x%x\n",
info->flags & ~XT_SOCKET_FLAGS_V3);
return -EINVAL;
}
- return 0;
+
+ return socket_mt_enable_defrag(par->net, par->family);
}
static void socket_mt_destroy(const struct xt_mtdtor_param *par)
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index e209099218b4..bbbde50fc649 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -2184,9 +2184,40 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
return err;
}
+static size_t ovs_vport_cmd_msg_size(void)
+{
+ size_t msgsize = NLMSG_ALIGN(sizeof(struct ovs_header));
+
+ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_PORT_NO */
+ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_TYPE */
+ msgsize += nla_total_size(IFNAMSIZ); /* OVS_VPORT_ATTR_NAME */
+ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_IFINDEX */
+ msgsize += nla_total_size(sizeof(s32)); /* OVS_VPORT_ATTR_NETNSID */
+
+ /* OVS_VPORT_ATTR_STATS */
+ msgsize += nla_total_size_64bit(sizeof(struct ovs_vport_stats));
+
+ /* OVS_VPORT_ATTR_UPCALL_STATS(OVS_VPORT_UPCALL_ATTR_SUCCESS +
+ * OVS_VPORT_UPCALL_ATTR_FAIL)
+ */
+ msgsize += nla_total_size(nla_total_size_64bit(sizeof(u64)) +
+ nla_total_size_64bit(sizeof(u64)));
+
+ /* OVS_VPORT_ATTR_UPCALL_PID */
+ msgsize += nla_total_size(nr_cpu_ids * sizeof(u32));
+
+ /* OVS_VPORT_ATTR_OPTIONS(OVS_TUNNEL_ATTR_DST_PORT +
+ * OVS_TUNNEL_ATTR_EXTENSION(OVS_VXLAN_EXT_GBP))
+ */
+ msgsize += nla_total_size(nla_total_size(sizeof(u16)) +
+ nla_total_size(nla_total_size(0)));
+
+ return msgsize;
+}
+
static struct sk_buff *ovs_vport_cmd_alloc_info(void)
{
- return nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ return genlmsg_new(ovs_vport_cmd_msg_size(), GFP_KERNEL);
}
/* Called with ovs_mutex, only via ovs_dp_notify_wq(). */
@@ -2196,7 +2227,7 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net,
struct sk_buff *skb;
int retval;
- skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ skb = ovs_vport_cmd_alloc_info();
if (!skb)
return ERR_PTR(-ENOMEM);
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
index 23f629e94a36..56b2e2d1a749 100644
--- a/net/openvswitch/vport.c
+++ b/net/openvswitch/vport.c
@@ -406,6 +406,9 @@ int ovs_vport_set_upcall_portids(struct vport *vport, const struct nlattr *ids)
if (!nla_len(ids) || nla_len(ids) % sizeof(u32))
return -EINVAL;
+ if (nla_len(ids) / sizeof(u32) > nr_cpu_ids)
+ return -EINVAL;
+
old = ovsl_dereference(vport->upcall_portids);
vport_portids = kmalloc(sizeof(*vport_portids) + nla_len(ids),
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index 4423d483c630..bbd710d95b97 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -208,9 +208,15 @@ static int pn_socket_autobind(struct socket *sock)
sa.spn_family = AF_PHONET;
err = pn_socket_bind(sock, (struct sockaddr_unsized *)&sa,
sizeof(struct sockaddr_pn));
- if (err != -EINVAL)
+ /*
+ * pn_socket_bind() also returns -EINVAL when sk_state != TCP_CLOSE
+ * without a prior bind, so -EINVAL alone is not sufficient to infer
+ * that the socket was already bound. Only treat it as "already
+ * bound" when the port is non-zero; otherwise propagate the error
+ * instead of crashing the kernel.
+ */
+ if (err != -EINVAL || unlikely(!pn_port(pn_sk(sock->sk)->sobject)))
return err;
- BUG_ON(!pn_port(pn_sk(sock->sk)->sobject));
return 0; /* socket was already bound */
}
diff --git a/net/psp/psp-nl-gen.c b/net/psp/psp-nl-gen.c
index 22a48d0fa378..953309952cef 100644
--- a/net/psp/psp-nl-gen.c
+++ b/net/psp/psp-nl-gen.c
@@ -76,7 +76,7 @@ static const struct genl_split_ops psp_nl_ops[] = {
.post_doit = psp_device_unlock,
.policy = psp_dev_set_nl_policy,
.maxattr = PSP_A_DEV_PSP_VERSIONS_ENA,
- .flags = GENL_CMD_CAP_DO,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
},
{
.cmd = PSP_CMD_KEY_ROTATE,
@@ -85,7 +85,7 @@ static const struct genl_split_ops psp_nl_ops[] = {
.post_doit = psp_device_unlock,
.policy = psp_key_rotate_nl_policy,
.maxattr = PSP_A_DEV_ID,
- .flags = GENL_CMD_CAP_DO,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
},
{
.cmd = PSP_CMD_RX_ASSOC,
diff --git a/net/psp/psp_nl.c b/net/psp/psp_nl.c
index 6afd7707ec12..0cc744a6e1c9 100644
--- a/net/psp/psp_nl.c
+++ b/net/psp/psp_nl.c
@@ -305,8 +305,13 @@ int psp_assoc_device_get_locked(const struct genl_split_ops *ops,
psd = psp_dev_get_for_sock(socket->sk);
if (psd) {
- err = psp_dev_check_access(psd, genl_info_net(info));
- if (err) {
+ /* Extra care needed here, psp_dev_get_for_sock() only gives
+ * us access to struct psp_dev's memory, which is quite weak.
+ */
+ mutex_lock(&psd->lock);
+ if (!psp_dev_is_registered(psd) ||
+ psp_dev_check_access(psd, genl_info_net(info))) {
+ mutex_unlock(&psd->lock);
psp_dev_put(psd);
psd = NULL;
}
@@ -319,7 +324,6 @@ int psp_assoc_device_get_locked(const struct genl_split_ops *ops,
id = info->attrs[PSP_A_ASSOC_DEV_ID];
if (psd) {
- mutex_lock(&psd->lock);
if (id && psd->id != nla_get_u32(id)) {
mutex_unlock(&psd->lock);
NL_SET_ERR_MSG_ATTR(info->extack, id,
diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c
index b396c673dfaf..76f625986a7f 100644
--- a/net/rds/af_rds.c
+++ b/net/rds/af_rds.c
@@ -357,7 +357,8 @@ static int rds_cong_monitor(struct rds_sock *rs, sockptr_t optval, int optlen)
return ret;
}
-static int rds_set_transport(struct rds_sock *rs, sockptr_t optval, int optlen)
+static int rds_set_transport(struct net *net, struct rds_sock *rs,
+ sockptr_t optval, int optlen)
{
int t_type;
@@ -373,6 +374,10 @@ static int rds_set_transport(struct rds_sock *rs, sockptr_t optval, int optlen)
if (t_type < 0 || t_type >= RDS_TRANS_COUNT)
return -EINVAL;
+ /* RDS/IB is restricted to the initial network namespace */
+ if (t_type != RDS_TRANS_TCP && !net_eq(net, &init_net))
+ return -EPROTOTYPE;
+
rs->rs_transport = rds_trans_get(t_type);
return rs->rs_transport ? 0 : -ENOPROTOOPT;
@@ -433,6 +438,7 @@ static int rds_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int optlen)
{
struct rds_sock *rs = rds_sk_to_rs(sock->sk);
+ struct net *net = sock_net(sock->sk);
int ret;
if (level != SOL_RDS) {
@@ -461,7 +467,7 @@ static int rds_setsockopt(struct socket *sock, int level, int optname,
break;
case SO_RDS_TRANSPORT:
lock_sock(sock->sk);
- ret = rds_set_transport(rs, optval, optlen);
+ ret = rds_set_transport(net, rs, optval, optlen);
release_sock(sock->sk);
break;
case SO_TIMESTAMP_OLD:
diff --git a/net/rds/connection.c b/net/rds/connection.c
index 412441aaa298..c10b7ed06c49 100644
--- a/net/rds/connection.c
+++ b/net/rds/connection.c
@@ -701,6 +701,13 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len,
i++, head++) {
hlist_for_each_entry_rcu(conn, head, c_hash_node) {
+ /* Zero the per-item buffer before handing it to the
+ * visitor so any field the visitor does not write -
+ * including implicit alignment padding - cannot leak
+ * stack contents to user space via rds_info_copy().
+ */
+ memset(buffer, 0, item_len);
+
/* XXX no c_lock usage.. */
if (!visitor(conn, buffer))
continue;
@@ -750,6 +757,13 @@ static void rds_walk_conn_path_info(struct socket *sock, unsigned int len,
*/
cp = conn->c_path;
+ /* Zero the per-item buffer for the same reason as
+ * rds_for_each_conn_info(): any byte the visitor
+ * does not write (including alignment padding) must
+ * not leak stack contents via rds_info_copy().
+ */
+ memset(buffer, 0, item_len);
+
/* XXX no cp_lock usage.. */
if (!visitor(cp, buffer))
continue;
diff --git a/net/rds/ib.c b/net/rds/ib.c
index ac6affa33ce7..39f87272e071 100644
--- a/net/rds/ib.c
+++ b/net/rds/ib.c
@@ -401,8 +401,8 @@ static void rds6_ib_ic_info(struct socket *sock, unsigned int len,
* allowed to influence which paths have priority. We could call userspace
* asserting this policy "routing".
*/
-static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr,
- __u32 scope_id)
+static int rds_ib_laddr_check_cm(struct net *net, const struct in6_addr *addr,
+ __u32 scope_id)
{
int ret;
struct rdma_cm_id *cm_id;
@@ -487,6 +487,26 @@ static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr,
return ret;
}
+static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr,
+ __u32 scope_id)
+{
+ struct rds_ib_device *rds_ibdev = NULL;
+
+ /* RDS/IB is restricted to the initial network namespace */
+ if (!net_eq(net, &init_net))
+ return -EPROTOTYPE;
+
+ if (ipv6_addr_v4mapped(addr)) {
+ rds_ibdev = rds_ib_get_device(addr->s6_addr32[3]);
+ if (rds_ibdev) {
+ rds_ib_dev_put(rds_ibdev);
+ return 0;
+ }
+ }
+
+ return rds_ib_laddr_check_cm(net, addr, scope_id);
+}
+
static void rds_ib_unregister_client(void)
{
ib_unregister_client(&rds_ib_client);
diff --git a/net/rds/ib.h b/net/rds/ib.h
index 8ef3178ed4d6..5ff346a1e8ba 100644
--- a/net/rds/ib.h
+++ b/net/rds/ib.h
@@ -381,6 +381,7 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn,
__rds_ib_conn_error(conn, KERN_WARNING "RDS/IB: " fmt)
/* ib_rdma.c */
+struct rds_ib_device *rds_ib_get_device(__be32 ipaddr);
int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev,
struct in6_addr *ipaddr);
void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn);
diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c
index 2cfec252eeac..9594ea245f7f 100644
--- a/net/rds/ib_rdma.c
+++ b/net/rds/ib_rdma.c
@@ -43,7 +43,7 @@ struct workqueue_struct *rds_ib_mr_wq;
static void rds_ib_odp_mr_worker(struct work_struct *work);
-static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr)
+struct rds_ib_device *rds_ib_get_device(__be32 ipaddr)
{
struct rds_ib_device *rds_ibdev;
struct rds_ib_ipaddr *i_ipaddr;
diff --git a/net/rds/message.c b/net/rds/message.c
index 25fedcb3cd00..7feb0eb6537d 100644
--- a/net/rds/message.c
+++ b/net/rds/message.c
@@ -448,6 +448,7 @@ static int rds_message_zcopy_from_user(struct rds_message *rm, struct iov_iter *
for (i = 0; i < rm->data.op_nents; i++)
put_page(sg_page(&rm->data.op_sg[i]));
+ rm->data.op_nents = 0;
mmp = &rm->data.op_mmp_znotifier->z_mmp;
mm_unaccount_pinned_pages(mmp);
ret = -EFAULT;
diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c
index 7d5e50c921a0..6158e13c98d3 100644
--- a/net/sched/act_ct.c
+++ b/net/sched/act_ct.c
@@ -328,9 +328,13 @@ static int tcf_ct_flow_table_get(struct net *net, struct tcf_ct_params *params)
int err = -ENOMEM;
mutex_lock(&zones_mutex);
- ct_ft = rhashtable_lookup_fast(&zones_ht, &key, zones_params);
- if (ct_ft && refcount_inc_not_zero(&ct_ft->ref))
+ rcu_read_lock();
+ ct_ft = rhashtable_lookup(&zones_ht, &key, zones_params);
+ if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) {
+ rcu_read_unlock();
goto out_unlock;
+ }
+ rcu_read_unlock();
ct_ft = kzalloc_obj(*ct_ft);
if (!ct_ft)
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index 05e0b14b5773..2c5a7a321a94 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -354,7 +354,7 @@ static int tcf_blockcast_redir(struct sk_buff *skb, struct tcf_mirred *m,
goto assign_prev;
tcf_mirred_to_dev(skb, m, dev_prev,
- dev_is_mac_header_xmit(dev),
+ dev_is_mac_header_xmit(dev_prev),
mirred_eaction, retval);
assign_prev:
dev_prev = dev;
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
index 23884ef8b80c..646a730dca93 100644
--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -74,9 +74,13 @@ TC_INDIRECT_SCOPE int fw_classify(struct sk_buff *skb,
}
}
} else {
- struct Qdisc *q = tcf_block_q(tp->chain->block);
+ struct Qdisc *q;
/* Old method: classify the packet using its skb mark. */
+ if (tcf_block_shared(tp->chain->block))
+ return -1;
+
+ q = tcf_block_q(tp->chain->block);
if (id && (TC_H_MAJ(id) == 0 ||
!(TC_H_MAJ(id ^ q->handle)))) {
res->classid = id;
diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c
index 9efe23f8371b..7033f859a394 100644
--- a/net/sched/sch_cake.c
+++ b/net/sched/sch_cake.c
@@ -619,7 +619,7 @@ static bool cake_update_flowkeys(struct flow_keys *keys,
}
port = rev ? tuple.src.u.all : tuple.dst.u.all;
if (port != keys->ports.dst) {
- port = keys->ports.dst;
+ keys->ports.dst = port;
upd = true;
}
}
@@ -813,7 +813,7 @@ static u32 cake_hash(struct cake_tin_data *q, const struct sk_buff *skb,
i++, k = (k + 1) % CAKE_SET_WAYS) {
if (q->tags[outer_hash + k] == flow_hash) {
if (i)
- q->way_hits++;
+ WRITE_ONCE(q->way_hits, q->way_hits + 1);
if (!q->flows[outer_hash + k].set) {
/* need to increment host refcnts */
@@ -831,7 +831,7 @@ static u32 cake_hash(struct cake_tin_data *q, const struct sk_buff *skb,
for (i = 0; i < CAKE_SET_WAYS;
i++, k = (k + 1) % CAKE_SET_WAYS) {
if (!q->flows[outer_hash + k].set) {
- q->way_misses++;
+ WRITE_ONCE(q->way_misses, q->way_misses + 1);
allocate_src = cake_dsrc(flow_mode);
allocate_dst = cake_ddst(flow_mode);
goto found;
@@ -841,7 +841,7 @@ static u32 cake_hash(struct cake_tin_data *q, const struct sk_buff *skb,
/* With no empty queues, default to the original
* queue, accept the collision, update the host tags.
*/
- q->way_collisions++;
+ WRITE_ONCE(q->way_collisions, q->way_collisions + 1);
allocate_src = cake_dsrc(flow_mode);
allocate_dst = cake_ddst(flow_mode);
@@ -1379,9 +1379,9 @@ static u32 cake_calc_overhead(struct cake_sched_data *qd, u32 len, u32 off)
len -= off;
if (qd->max_netlen < len)
- qd->max_netlen = len;
+ WRITE_ONCE(qd->max_netlen, len);
if (qd->min_netlen > len)
- qd->min_netlen = len;
+ WRITE_ONCE(qd->min_netlen, len);
len += q->rate_overhead;
@@ -1401,9 +1401,9 @@ static u32 cake_calc_overhead(struct cake_sched_data *qd, u32 len, u32 off)
}
if (qd->max_adjlen < len)
- qd->max_adjlen = len;
+ WRITE_ONCE(qd->max_adjlen, len);
if (qd->min_adjlen > len)
- qd->min_adjlen = len;
+ WRITE_ONCE(qd->min_adjlen, len);
return len;
}
@@ -1416,7 +1416,7 @@ static u32 cake_overhead(struct cake_sched_data *q, const struct sk_buff *skb)
u16 segs = qdisc_pkt_segs(skb);
u32 len = qdisc_pkt_len(skb);
- q->avg_netoff = cake_ewma(q->avg_netoff, off << 16, 8);
+ WRITE_ONCE(q->avg_netoff, cake_ewma(q->avg_netoff, off << 16, 8));
if (segs == 1)
return cake_calc_overhead(q, len, off);
@@ -1590,16 +1590,17 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free)
}
if (cobalt_queue_full(&flow->cvars, &b->cparams, now))
- b->unresponsive_flow_count++;
+ WRITE_ONCE(b->unresponsive_flow_count,
+ b->unresponsive_flow_count + 1);
len = qdisc_pkt_len(skb);
q->buffer_used -= skb->truesize;
b->backlogs[idx] -= len;
- b->tin_backlog -= len;
+ WRITE_ONCE(b->tin_backlog, b->tin_backlog - len);
sch->qstats.backlog -= len;
flow->dropped++;
- b->tin_dropped++;
+ WRITE_ONCE(b->tin_dropped, b->tin_dropped + 1);
if (q->config->rate_flags & CAKE_FLAG_INGRESS)
cake_advance_shaper(q, b, skb, now, true);
@@ -1795,7 +1796,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
}
if (unlikely(len > b->max_skblen))
- b->max_skblen = len;
+ WRITE_ONCE(b->max_skblen, len);
if (qdisc_pkt_segs(skb) > 1 && q->config->rate_flags & CAKE_FLAG_SPLIT_GSO) {
struct sk_buff *segs, *nskb;
@@ -1819,15 +1820,15 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
numsegs++;
slen += segs->len;
q->buffer_used += segs->truesize;
- b->packets++;
+ WRITE_ONCE(b->packets, b->packets + 1);
}
/* stats */
- b->bytes += slen;
b->backlogs[idx] += slen;
- b->tin_backlog += slen;
sch->qstats.backlog += slen;
q->avg_window_bytes += slen;
+ WRITE_ONCE(b->bytes, b->bytes + slen);
+ WRITE_ONCE(b->tin_backlog, b->tin_backlog + slen);
qdisc_tree_reduce_backlog(sch, 1-numsegs, len-slen);
consume_skb(skb);
@@ -1843,10 +1844,10 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
ack = cake_ack_filter(q, flow);
if (ack) {
- b->ack_drops++;
+ WRITE_ONCE(b->ack_drops, b->ack_drops + 1);
sch->qstats.drops++;
ack_pkt_len = qdisc_pkt_len(ack);
- b->bytes += ack_pkt_len;
+ WRITE_ONCE(b->bytes, b->bytes + ack_pkt_len);
q->buffer_used += skb->truesize - ack->truesize;
if (q->config->rate_flags & CAKE_FLAG_INGRESS)
cake_advance_shaper(q, b, ack, now, true);
@@ -1859,12 +1860,12 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
}
/* stats */
- b->packets++;
- b->bytes += len - ack_pkt_len;
+ WRITE_ONCE(b->packets, b->packets + 1);
b->backlogs[idx] += len - ack_pkt_len;
- b->tin_backlog += len - ack_pkt_len;
sch->qstats.backlog += len - ack_pkt_len;
q->avg_window_bytes += len - ack_pkt_len;
+ WRITE_ONCE(b->bytes, b->bytes + len - ack_pkt_len);
+ WRITE_ONCE(b->tin_backlog, b->tin_backlog + len - ack_pkt_len);
}
if (q->overflow_timeout)
@@ -1894,9 +1895,9 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
u64 b = q->avg_window_bytes * (u64)NSEC_PER_SEC;
b = div64_u64(b, window_interval);
- q->avg_peak_bandwidth =
- cake_ewma(q->avg_peak_bandwidth, b,
- b > q->avg_peak_bandwidth ? 2 : 8);
+ WRITE_ONCE(q->avg_peak_bandwidth,
+ cake_ewma(q->avg_peak_bandwidth, b,
+ b > q->avg_peak_bandwidth ? 2 : 8));
q->avg_window_bytes = 0;
q->avg_window_begin = now;
@@ -1917,11 +1918,11 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
if (!flow->set) {
list_add_tail(&flow->flowchain, &b->new_flows);
} else {
- b->decaying_flow_count--;
+ WRITE_ONCE(b->decaying_flow_count, b->decaying_flow_count - 1);
list_move_tail(&flow->flowchain, &b->new_flows);
}
flow->set = CAKE_SET_SPARSE;
- b->sparse_flow_count++;
+ WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count + 1);
flow->deficit = cake_get_flow_quantum(b, flow, q->config->flow_mode);
} else if (flow->set == CAKE_SET_SPARSE_WAIT) {
@@ -1929,15 +1930,15 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
* in the bulk rotation.
*/
flow->set = CAKE_SET_BULK;
- b->sparse_flow_count--;
- b->bulk_flow_count++;
+ WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count - 1);
+ WRITE_ONCE(b->bulk_flow_count, b->bulk_flow_count + 1);
cake_inc_srchost_bulk_flow_count(b, flow, q->config->flow_mode);
cake_inc_dsthost_bulk_flow_count(b, flow, q->config->flow_mode);
}
if (q->buffer_used > q->buffer_max_used)
- q->buffer_max_used = q->buffer_used;
+ WRITE_ONCE(q->buffer_max_used, q->buffer_used);
if (q->buffer_used <= q->buffer_limit)
return NET_XMIT_SUCCESS;
@@ -1977,7 +1978,7 @@ static struct sk_buff *cake_dequeue_one(struct Qdisc *sch)
skb = dequeue_head(flow);
len = qdisc_pkt_len(skb);
b->backlogs[q->cur_flow] -= len;
- b->tin_backlog -= len;
+ WRITE_ONCE(b->tin_backlog, b->tin_backlog - len);
sch->qstats.backlog -= len;
q->buffer_used -= skb->truesize;
sch->q.qlen--;
@@ -2042,7 +2043,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
cake_configure_rates(sch, new_rate, true);
q->last_checked_active = now;
- q->active_queues = num_active_qs;
+ WRITE_ONCE(q->active_queues, num_active_qs);
}
begin:
@@ -2149,8 +2150,8 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
*/
if (flow->set == CAKE_SET_SPARSE) {
if (flow->head) {
- b->sparse_flow_count--;
- b->bulk_flow_count++;
+ WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count - 1);
+ WRITE_ONCE(b->bulk_flow_count, b->bulk_flow_count + 1);
cake_inc_srchost_bulk_flow_count(b, flow, q->config->flow_mode);
cake_inc_dsthost_bulk_flow_count(b, flow, q->config->flow_mode);
@@ -2177,7 +2178,8 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
if (!skb) {
/* this queue was actually empty */
if (cobalt_queue_empty(&flow->cvars, &b->cparams, now))
- b->unresponsive_flow_count--;
+ WRITE_ONCE(b->unresponsive_flow_count,
+ b->unresponsive_flow_count - 1);
if (flow->cvars.p_drop || flow->cvars.count ||
ktime_before(now, flow->cvars.drop_next)) {
@@ -2187,32 +2189,32 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
list_move_tail(&flow->flowchain,
&b->decaying_flows);
if (flow->set == CAKE_SET_BULK) {
- b->bulk_flow_count--;
+ WRITE_ONCE(b->bulk_flow_count, b->bulk_flow_count - 1);
cake_dec_srchost_bulk_flow_count(b, flow, q->config->flow_mode);
cake_dec_dsthost_bulk_flow_count(b, flow, q->config->flow_mode);
- b->decaying_flow_count++;
+ WRITE_ONCE(b->decaying_flow_count, b->decaying_flow_count + 1);
} else if (flow->set == CAKE_SET_SPARSE ||
flow->set == CAKE_SET_SPARSE_WAIT) {
- b->sparse_flow_count--;
- b->decaying_flow_count++;
+ WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count - 1);
+ WRITE_ONCE(b->decaying_flow_count, b->decaying_flow_count + 1);
}
flow->set = CAKE_SET_DECAYING;
} else {
/* remove empty queue from the flowchain */
list_del_init(&flow->flowchain);
if (flow->set == CAKE_SET_SPARSE ||
- flow->set == CAKE_SET_SPARSE_WAIT)
- b->sparse_flow_count--;
- else if (flow->set == CAKE_SET_BULK) {
- b->bulk_flow_count--;
+ flow->set == CAKE_SET_SPARSE_WAIT) {
+ WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count - 1);
+ } else if (flow->set == CAKE_SET_BULK) {
+ WRITE_ONCE(b->bulk_flow_count, b->bulk_flow_count - 1);
cake_dec_srchost_bulk_flow_count(b, flow, q->config->flow_mode);
cake_dec_dsthost_bulk_flow_count(b, flow, q->config->flow_mode);
- } else
- b->decaying_flow_count--;
-
+ } else {
+ WRITE_ONCE(b->decaying_flow_count, b->decaying_flow_count - 1);
+ }
flow->set = CAKE_SET_NONE;
}
goto begin;
@@ -2234,7 +2236,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
b->tin_deficit -= len;
}
flow->dropped++;
- b->tin_dropped++;
+ WRITE_ONCE(b->tin_dropped, b->tin_dropped + 1);
qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(skb));
qdisc_qstats_drop(sch);
qdisc_dequeue_drop(sch, skb, reason);
@@ -2242,17 +2244,19 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
goto retry;
}
- b->tin_ecn_mark += !!flow->cvars.ecn_marked;
+ WRITE_ONCE(b->tin_ecn_mark, b->tin_ecn_mark + !!flow->cvars.ecn_marked);
qdisc_bstats_update(sch, skb);
WRITE_ONCE(q->last_active, now);
/* collect delay stats */
delay = ktime_to_ns(ktime_sub(now, cobalt_get_enqueue_time(skb)));
- b->avge_delay = cake_ewma(b->avge_delay, delay, 8);
- b->peak_delay = cake_ewma(b->peak_delay, delay,
- delay > b->peak_delay ? 2 : 8);
- b->base_delay = cake_ewma(b->base_delay, delay,
- delay < b->base_delay ? 2 : 8);
+ WRITE_ONCE(b->avge_delay, cake_ewma(b->avge_delay, delay, 8));
+ WRITE_ONCE(b->peak_delay,
+ cake_ewma(b->peak_delay, delay,
+ delay > b->peak_delay ? 2 : 8));
+ WRITE_ONCE(b->base_delay,
+ cake_ewma(b->base_delay, delay,
+ delay < b->base_delay ? 2 : 8));
len = cake_advance_shaper(q, b, skb, now, false);
flow->deficit -= len;
@@ -2329,9 +2333,9 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu,
u8 rate_shft = 0;
u64 rate_ns = 0;
- b->flow_quantum = 1514;
if (rate) {
- b->flow_quantum = max(min(rate >> 12, 1514ULL), 300ULL);
+ WRITE_ONCE(b->flow_quantum,
+ max(min(rate >> 12, 1514ULL), 300ULL));
rate_shft = 34;
rate_ns = ((u64)NSEC_PER_SEC) << rate_shft;
rate_ns = div64_u64(rate_ns, max(MIN_RATE, rate));
@@ -2339,9 +2343,11 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu,
rate_ns >>= 1;
rate_shft--;
}
- } /* else unlimited, ie. zero delay */
-
- b->tin_rate_bps = rate;
+ } else {
+ /* else unlimited, ie. zero delay */
+ WRITE_ONCE(b->flow_quantum, 1514);
+ }
+ WRITE_ONCE(b->tin_rate_bps, rate);
b->tin_rate_ns = rate_ns;
b->tin_rate_shft = rate_shft;
@@ -2350,10 +2356,11 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu,
byte_target_ns = (byte_target * rate_ns) >> rate_shft;
- b->cparams.target = max((byte_target_ns * 3) / 2, target_ns);
- b->cparams.interval = max(rtt_est_ns +
- b->cparams.target - target_ns,
- b->cparams.target * 2);
+ WRITE_ONCE(b->cparams.target,
+ max((byte_target_ns * 3) / 2, target_ns));
+ WRITE_ONCE(b->cparams.interval,
+ max(rtt_est_ns + b->cparams.target - target_ns,
+ b->cparams.target * 2));
b->cparams.mtu_time = byte_target_ns;
b->cparams.p_inc = 1 << 24; /* 1/256 */
b->cparams.p_dec = 1 << 20; /* 1/4096 */
@@ -2611,25 +2618,27 @@ static void cake_reconfigure(struct Qdisc *sch)
{
struct cake_sched_data *qd = qdisc_priv(sch);
struct cake_sched_config *q = qd->config;
+ u32 buffer_limit;
cake_configure_rates(sch, qd->config->rate_bps, false);
if (q->buffer_config_limit) {
- qd->buffer_limit = q->buffer_config_limit;
+ buffer_limit = q->buffer_config_limit;
} else if (q->rate_bps) {
u64 t = q->rate_bps * q->interval;
do_div(t, USEC_PER_SEC / 4);
- qd->buffer_limit = max_t(u32, t, 4U << 20);
+ buffer_limit = max_t(u32, t, 4U << 20);
} else {
- qd->buffer_limit = ~0;
+ buffer_limit = ~0;
}
sch->flags &= ~TCQ_F_CAN_BYPASS;
- qd->buffer_limit = min(qd->buffer_limit,
- max(sch->limit * psched_mtu(qdisc_dev(sch)),
- q->buffer_config_limit));
+ WRITE_ONCE(qd->buffer_limit,
+ min(buffer_limit,
+ max(sch->limit * psched_mtu(qdisc_dev(sch)),
+ q->buffer_config_limit)));
}
static int cake_config_change(struct cake_sched_config *q, struct nlattr *opt,
@@ -2774,10 +2783,10 @@ static int cake_change(struct Qdisc *sch, struct nlattr *opt,
return ret;
if (overhead_changed) {
- qd->max_netlen = 0;
- qd->max_adjlen = 0;
- qd->min_netlen = ~0;
- qd->min_adjlen = ~0;
+ WRITE_ONCE(qd->max_netlen, 0);
+ WRITE_ONCE(qd->max_adjlen, 0);
+ WRITE_ONCE(qd->min_netlen, ~0);
+ WRITE_ONCE(qd->min_adjlen, ~0);
}
if (qd->tins) {
@@ -2995,15 +3004,15 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
goto nla_put_failure; \
} while (0)
- PUT_STAT_U64(CAPACITY_ESTIMATE64, q->avg_peak_bandwidth);
- PUT_STAT_U32(MEMORY_LIMIT, q->buffer_limit);
- PUT_STAT_U32(MEMORY_USED, q->buffer_max_used);
- PUT_STAT_U32(AVG_NETOFF, ((q->avg_netoff + 0x8000) >> 16));
- PUT_STAT_U32(MAX_NETLEN, q->max_netlen);
- PUT_STAT_U32(MAX_ADJLEN, q->max_adjlen);
- PUT_STAT_U32(MIN_NETLEN, q->min_netlen);
- PUT_STAT_U32(MIN_ADJLEN, q->min_adjlen);
- PUT_STAT_U32(ACTIVE_QUEUES, q->active_queues);
+ PUT_STAT_U64(CAPACITY_ESTIMATE64, READ_ONCE(q->avg_peak_bandwidth));
+ PUT_STAT_U32(MEMORY_LIMIT, READ_ONCE(q->buffer_limit));
+ PUT_STAT_U32(MEMORY_USED, READ_ONCE(q->buffer_max_used));
+ PUT_STAT_U32(AVG_NETOFF, ((READ_ONCE(q->avg_netoff) + 0x8000) >> 16));
+ PUT_STAT_U32(MAX_NETLEN, READ_ONCE(q->max_netlen));
+ PUT_STAT_U32(MAX_ADJLEN, READ_ONCE(q->max_adjlen));
+ PUT_STAT_U32(MIN_NETLEN, READ_ONCE(q->min_netlen));
+ PUT_STAT_U32(MIN_ADJLEN, READ_ONCE(q->min_adjlen));
+ PUT_STAT_U32(ACTIVE_QUEUES, READ_ONCE(q->active_queues));
#undef PUT_STAT_U32
#undef PUT_STAT_U64
@@ -3029,38 +3038,38 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
if (!ts)
goto nla_put_failure;
- PUT_TSTAT_U64(THRESHOLD_RATE64, b->tin_rate_bps);
- PUT_TSTAT_U64(SENT_BYTES64, b->bytes);
- PUT_TSTAT_U32(BACKLOG_BYTES, b->tin_backlog);
+ PUT_TSTAT_U64(THRESHOLD_RATE64, READ_ONCE(b->tin_rate_bps));
+ PUT_TSTAT_U64(SENT_BYTES64, READ_ONCE(b->bytes));
+ PUT_TSTAT_U32(BACKLOG_BYTES, READ_ONCE(b->tin_backlog));
PUT_TSTAT_U32(TARGET_US,
- ktime_to_us(ns_to_ktime(b->cparams.target)));
+ ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.target))));
PUT_TSTAT_U32(INTERVAL_US,
- ktime_to_us(ns_to_ktime(b->cparams.interval)));
+ ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.interval))));
- PUT_TSTAT_U32(SENT_PACKETS, b->packets);
- PUT_TSTAT_U32(DROPPED_PACKETS, b->tin_dropped);
- PUT_TSTAT_U32(ECN_MARKED_PACKETS, b->tin_ecn_mark);
- PUT_TSTAT_U32(ACKS_DROPPED_PACKETS, b->ack_drops);
+ PUT_TSTAT_U32(SENT_PACKETS, READ_ONCE(b->packets));
+ PUT_TSTAT_U32(DROPPED_PACKETS, READ_ONCE(b->tin_dropped));
+ PUT_TSTAT_U32(ECN_MARKED_PACKETS, READ_ONCE(b->tin_ecn_mark));
+ PUT_TSTAT_U32(ACKS_DROPPED_PACKETS, READ_ONCE(b->ack_drops));
PUT_TSTAT_U32(PEAK_DELAY_US,
- ktime_to_us(ns_to_ktime(b->peak_delay)));
+ ktime_to_us(ns_to_ktime(READ_ONCE(b->peak_delay))));
PUT_TSTAT_U32(AVG_DELAY_US,
- ktime_to_us(ns_to_ktime(b->avge_delay)));
+ ktime_to_us(ns_to_ktime(READ_ONCE(b->avge_delay))));
PUT_TSTAT_U32(BASE_DELAY_US,
- ktime_to_us(ns_to_ktime(b->base_delay)));
+ ktime_to_us(ns_to_ktime(READ_ONCE(b->base_delay))));
- PUT_TSTAT_U32(WAY_INDIRECT_HITS, b->way_hits);
- PUT_TSTAT_U32(WAY_MISSES, b->way_misses);
- PUT_TSTAT_U32(WAY_COLLISIONS, b->way_collisions);
+ PUT_TSTAT_U32(WAY_INDIRECT_HITS, READ_ONCE(b->way_hits));
+ PUT_TSTAT_U32(WAY_MISSES, READ_ONCE(b->way_misses));
+ PUT_TSTAT_U32(WAY_COLLISIONS, READ_ONCE(b->way_collisions));
- PUT_TSTAT_U32(SPARSE_FLOWS, b->sparse_flow_count +
- b->decaying_flow_count);
- PUT_TSTAT_U32(BULK_FLOWS, b->bulk_flow_count);
- PUT_TSTAT_U32(UNRESPONSIVE_FLOWS, b->unresponsive_flow_count);
- PUT_TSTAT_U32(MAX_SKBLEN, b->max_skblen);
+ PUT_TSTAT_U32(SPARSE_FLOWS, READ_ONCE(b->sparse_flow_count) +
+ READ_ONCE(b->decaying_flow_count));
+ PUT_TSTAT_U32(BULK_FLOWS, READ_ONCE(b->bulk_flow_count));
+ PUT_TSTAT_U32(UNRESPONSIVE_FLOWS, READ_ONCE(b->unresponsive_flow_count));
+ PUT_TSTAT_U32(MAX_SKBLEN, READ_ONCE(b->max_skblen));
- PUT_TSTAT_U32(FLOW_QUANTUM, b->flow_quantum);
+ PUT_TSTAT_U32(FLOW_QUANTUM, READ_ONCE(b->flow_quantum));
nla_nest_end(d->skb, ts);
}
@@ -3298,10 +3307,10 @@ static int cake_mq_change(struct Qdisc *sch, struct nlattr *opt,
struct cake_sched_data *qd = qdisc_priv(chld);
if (overhead_changed) {
- qd->max_netlen = 0;
- qd->max_adjlen = 0;
- qd->min_netlen = ~0;
- qd->min_adjlen = ~0;
+ WRITE_ONCE(qd->max_netlen, 0);
+ WRITE_ONCE(qd->max_adjlen, 0);
+ WRITE_ONCE(qd->min_netlen, ~0);
+ WRITE_ONCE(qd->min_adjlen, ~0);
}
if (qd->tins) {
diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c
index 94df8e741a97..2875bcdb18a4 100644
--- a/net/sched/sch_choke.c
+++ b/net/sched/sch_choke.c
@@ -229,7 +229,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch,
/* Draw a packet at random from queue and compare flow */
if (choke_match_random(q, skb, &idx)) {
- q->stats.matched++;
+ WRITE_ONCE(q->stats.matched, q->stats.matched + 1);
choke_drop_by_idx(sch, idx, to_free);
goto congestion_drop;
}
@@ -241,11 +241,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch,
qdisc_qstats_overlimit(sch);
if (use_harddrop(q) || !use_ecn(q) ||
!INET_ECN_set_ce(skb)) {
- q->stats.forced_drop++;
+ WRITE_ONCE(q->stats.forced_drop,
+ q->stats.forced_drop + 1);
goto congestion_drop;
}
- q->stats.forced_mark++;
+ WRITE_ONCE(q->stats.forced_mark,
+ q->stats.forced_mark + 1);
} else if (++q->vars.qcount) {
if (red_mark_probability(p, &q->vars, q->vars.qavg)) {
q->vars.qcount = 0;
@@ -253,11 +255,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch,
qdisc_qstats_overlimit(sch);
if (!use_ecn(q) || !INET_ECN_set_ce(skb)) {
- q->stats.prob_drop++;
+ WRITE_ONCE(q->stats.prob_drop,
+ q->stats.prob_drop + 1);
goto congestion_drop;
}
- q->stats.prob_mark++;
+ WRITE_ONCE(q->stats.prob_mark,
+ q->stats.prob_mark + 1);
}
} else
q->vars.qR = red_random(p);
@@ -272,7 +276,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch,
return NET_XMIT_SUCCESS;
}
- q->stats.pdrop++;
+ WRITE_ONCE(q->stats.pdrop, q->stats.pdrop + 1);
return qdisc_drop(skb, sch, to_free);
congestion_drop:
@@ -461,10 +465,12 @@ static int choke_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
{
struct choke_sched_data *q = qdisc_priv(sch);
struct tc_choke_xstats st = {
- .early = q->stats.prob_drop + q->stats.forced_drop,
- .marked = q->stats.prob_mark + q->stats.forced_mark,
- .pdrop = q->stats.pdrop,
- .matched = q->stats.matched,
+ .early = READ_ONCE(q->stats.prob_drop) +
+ READ_ONCE(q->stats.forced_drop),
+ .marked = READ_ONCE(q->stats.prob_mark) +
+ READ_ONCE(q->stats.forced_mark),
+ .pdrop = READ_ONCE(q->stats.pdrop),
+ .matched = READ_ONCE(q->stats.matched),
};
return gnet_stats_copy_app(d, &st, sizeof(st));
diff --git a/net/sched/sch_dualpi2.c b/net/sched/sch_dualpi2.c
index 6d7e6389758d..d200c08ce50a 100644
--- a/net/sched/sch_dualpi2.c
+++ b/net/sched/sch_dualpi2.c
@@ -872,11 +872,35 @@ static int dualpi2_change(struct Qdisc *sch, struct nlattr *opt,
old_backlog = sch->qstats.backlog;
while (qdisc_qlen(sch) > sch->limit ||
q->memory_used > q->memory_limit) {
- struct sk_buff *skb = qdisc_dequeue_internal(sch, true);
+ struct sk_buff *skb = NULL;
- q->memory_used -= skb->truesize;
- qdisc_qstats_backlog_dec(sch, skb);
- rtnl_qdisc_drop(skb, sch);
+ if (qdisc_qlen(sch) > qdisc_qlen(q->l_queue)) {
+ skb = qdisc_dequeue_internal(sch, true);
+ if (unlikely(!skb)) {
+ WARN_ON_ONCE(1);
+ break;
+ }
+ q->memory_used -= skb->truesize;
+ rtnl_qdisc_drop(skb, sch);
+ } else if (qdisc_qlen(q->l_queue)) {
+ skb = qdisc_dequeue_internal(q->l_queue, true);
+ if (unlikely(!skb)) {
+ WARN_ON_ONCE(1);
+ break;
+ }
+ /* L-queue packets are counted in both sch and
+ * l_queue on enqueue; qdisc_dequeue_internal()
+ * handled l_queue, so we further account for sch.
+ */
+ --sch->q.qlen;
+ qdisc_qstats_backlog_dec(sch, skb);
+ q->memory_used -= skb->truesize;
+ rtnl_qdisc_drop(skb, q->l_queue);
+ qdisc_qstats_drop(sch);
+ } else {
+ WARN_ON_ONCE(1);
+ break;
+ }
}
qdisc_tree_reduce_backlog(sch, old_qlen - qdisc_qlen(sch),
old_backlog - sch->qstats.backlog);
diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c
index 8181b52dd9a8..84b84e3ad80d 100644
--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
@@ -585,6 +585,8 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
};
struct list_head *pos;
+ sch_tree_lock(sch);
+
st.qdisc_stats.maxpacket = q->cstats.maxpacket;
st.qdisc_stats.drop_overlimit = q->drop_overlimit;
st.qdisc_stats.ecn_mark = q->cstats.ecn_mark;
@@ -593,7 +595,6 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
st.qdisc_stats.memory_usage = q->memory_usage;
st.qdisc_stats.drop_overmemory = q->drop_overmemory;
- sch_tree_lock(sch);
list_for_each(pos, &q->new_flows)
st.qdisc_stats.new_flows_len++;
diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c
index d8ac3519e937..66ec15998ce0 100644
--- a/net/sched/sch_fq_pie.c
+++ b/net/sched/sch_fq_pie.c
@@ -509,18 +509,19 @@ static int fq_pie_dump(struct Qdisc *sch, struct sk_buff *skb)
static int fq_pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
{
struct fq_pie_sched_data *q = qdisc_priv(sch);
- struct tc_fq_pie_xstats st = {
- .packets_in = q->stats.packets_in,
- .overlimit = q->stats.overlimit,
- .overmemory = q->overmemory,
- .dropped = q->stats.dropped,
- .ecn_mark = q->stats.ecn_mark,
- .new_flow_count = q->new_flow_count,
- .memory_usage = q->memory_usage,
- };
+ struct tc_fq_pie_xstats st = { 0 };
struct list_head *pos;
sch_tree_lock(sch);
+
+ st.packets_in = q->stats.packets_in;
+ st.overlimit = q->stats.overlimit;
+ st.overmemory = q->overmemory;
+ st.dropped = q->stats.dropped;
+ st.ecn_mark = q->stats.ecn_mark;
+ st.new_flow_count = q->new_flow_count;
+ st.memory_usage = q->memory_usage;
+
list_for_each(pos, &q->new_flows)
st.new_flows_len++;
diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c
index 95e5d9bfd9c8..96021f52d835 100644
--- a/net/sched/sch_hhf.c
+++ b/net/sched/sch_hhf.c
@@ -198,7 +198,8 @@ static struct hh_flow_state *seek_list(const u32 hash,
return NULL;
list_del(&flow->flowchain);
kfree(flow);
- q->hh_flows_current_cnt--;
+ WRITE_ONCE(q->hh_flows_current_cnt,
+ q->hh_flows_current_cnt - 1);
} else if (flow->hash_id == hash) {
return flow;
}
@@ -226,7 +227,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head,
}
if (q->hh_flows_current_cnt >= q->hh_flows_limit) {
- q->hh_flows_overlimit++;
+ WRITE_ONCE(q->hh_flows_overlimit, q->hh_flows_overlimit + 1);
return NULL;
}
/* Create new entry. */
@@ -234,7 +235,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head,
if (!flow)
return NULL;
- q->hh_flows_current_cnt++;
+ WRITE_ONCE(q->hh_flows_current_cnt, q->hh_flows_current_cnt + 1);
INIT_LIST_HEAD(&flow->flowchain);
list_add_tail(&flow->flowchain, head);
@@ -309,7 +310,7 @@ static enum wdrr_bucket_idx hhf_classify(struct sk_buff *skb, struct Qdisc *sch)
return WDRR_BUCKET_FOR_NON_HH;
flow->hash_id = hash;
flow->hit_timestamp = now;
- q->hh_flows_total_cnt++;
+ WRITE_ONCE(q->hh_flows_total_cnt, q->hh_flows_total_cnt + 1);
/* By returning without updating counters in q->hhf_arrays,
* we implicitly implement "shielding" (see Optimization O1).
@@ -403,7 +404,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch,
return NET_XMIT_SUCCESS;
prev_backlog = sch->qstats.backlog;
- q->drop_overlimit++;
+ WRITE_ONCE(q->drop_overlimit, q->drop_overlimit + 1);
/* Return Congestion Notification only if we dropped a packet from this
* bucket.
*/
@@ -686,10 +687,10 @@ static int hhf_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
{
struct hhf_sched_data *q = qdisc_priv(sch);
struct tc_hhf_xstats st = {
- .drop_overlimit = q->drop_overlimit,
- .hh_overlimit = q->hh_flows_overlimit,
- .hh_tot_count = q->hh_flows_total_cnt,
- .hh_cur_count = q->hh_flows_current_cnt,
+ .drop_overlimit = READ_ONCE(q->drop_overlimit),
+ .hh_overlimit = READ_ONCE(q->hh_flows_overlimit),
+ .hh_tot_count = READ_ONCE(q->hh_flows_total_cnt),
+ .hh_cur_count = READ_ONCE(q->hh_flows_current_cnt),
};
return gnet_stats_copy_app(d, &st, sizeof(st));
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 20df1c08b1e9..bc18e1976b6e 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -227,10 +227,10 @@ static bool loss_4state(struct netem_sched_data *q)
if (rnd < clg->a4) {
clg->state = LOST_IN_GAP_PERIOD;
return true;
- } else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) {
+ } else if (rnd < clg->a1 + clg->a4) {
clg->state = LOST_IN_BURST_PERIOD;
return true;
- } else if (clg->a1 + clg->a4 < rnd) {
+ } else {
clg->state = TX_IN_GAP_PERIOD;
}
@@ -247,9 +247,9 @@ static bool loss_4state(struct netem_sched_data *q)
case LOST_IN_BURST_PERIOD:
if (rnd < clg->a3)
clg->state = TX_IN_BURST_PERIOD;
- else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) {
+ else if (rnd < clg->a2 + clg->a3) {
clg->state = TX_IN_GAP_PERIOD;
- } else if (clg->a2 + clg->a3 < rnd) {
+ } else {
clg->state = LOST_IN_BURST_PERIOD;
return true;
}
@@ -524,7 +524,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
1 << get_random_u32_below(8);
}
- if (unlikely(q->t_len >= sch->limit)) {
+ if (unlikely(sch->q.qlen >= sch->limit)) {
/* re-link segs, so that qdisc_drop_all() frees them all */
skb->next = segs;
qdisc_drop_all(skb, sch, to_free);
@@ -659,9 +659,8 @@ static void get_slot_next(struct netem_sched_data *q, u64 now)
if (!q->slot_dist)
next_delay = q->slot_config.min_delay +
- (get_random_u32() *
- (q->slot_config.max_delay -
- q->slot_config.min_delay) >> 32);
+ mul_u64_u32_shr(q->slot_config.max_delay - q->slot_config.min_delay,
+ get_random_u32(), 32);
else
next_delay = tabledist(q->slot_config.dist_delay,
(s32)(q->slot_config.dist_jitter),
@@ -827,6 +826,39 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr)
return 0;
}
+static int validate_time(const struct nlattr *attr, const char *name,
+ struct netlink_ext_ack *extack)
+{
+ if (nla_get_s64(attr) < 0) {
+ NL_SET_ERR_MSG_ATTR_FMT(extack, attr, "negative %s", name);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int validate_slot(const struct nlattr *attr, struct netlink_ext_ack *extack)
+{
+ const struct tc_netem_slot *c = nla_data(attr);
+
+ if (c->min_delay < 0 || c->max_delay < 0) {
+ NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot delay");
+ return -EINVAL;
+ }
+ if (c->min_delay > c->max_delay) {
+ NL_SET_ERR_MSG_ATTR(extack, attr, "slot min delay greater than max delay");
+ return -EINVAL;
+ }
+ if (c->dist_delay < 0 || c->dist_jitter < 0) {
+ NL_SET_ERR_MSG_ATTR(extack, attr, "negative dist delay");
+ return -EINVAL;
+ }
+ if (c->max_packets < 0 || c->max_bytes < 0) {
+ NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot limit");
+ return -EINVAL;
+ }
+ return 0;
+}
+
static void get_slot(struct netem_sched_data *q, const struct nlattr *attr)
{
const struct tc_netem_slot *c = nla_data(attr);
@@ -1040,6 +1072,24 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
goto table_free;
}
+ if (tb[TCA_NETEM_SLOT]) {
+ ret = validate_slot(tb[TCA_NETEM_SLOT], extack);
+ if (ret)
+ goto table_free;
+ }
+
+ if (tb[TCA_NETEM_LATENCY64]) {
+ ret = validate_time(tb[TCA_NETEM_LATENCY64], "latency", extack);
+ if (ret)
+ goto table_free;
+ }
+
+ if (tb[TCA_NETEM_JITTER64]) {
+ ret = validate_time(tb[TCA_NETEM_JITTER64], "jitter", extack);
+ if (ret)
+ goto table_free;
+ }
+
sch_tree_lock(sch);
/* backup q->clg and q->loss_model */
old_clg = q->clg;
@@ -1112,11 +1162,10 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
/* capping jitter to the range acceptable by tabledist() */
q->jitter = min_t(s64, abs(q->jitter), INT_MAX);
- if (tb[TCA_NETEM_PRNG_SEED])
+ if (tb[TCA_NETEM_PRNG_SEED]) {
q->prng.seed = nla_get_u64(tb[TCA_NETEM_PRNG_SEED]);
- else
- q->prng.seed = get_random_u64();
- prandom_seed_state(&q->prng.prng_state, q->prng.seed);
+ prandom_seed_state(&q->prng.prng_state, q->prng.seed);
+ }
unlock:
sch_tree_unlock(sch);
@@ -1139,6 +1188,9 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt,
return -EINVAL;
q->loss_model = CLG_RANDOM;
+ q->prng.seed = get_random_u64();
+ prandom_seed_state(&q->prng.prng_state, q->prng.seed);
+
ret = netem_change(sch, opt, extack);
if (ret)
pr_info("netem: change failed\n");
diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c
index 0a377313b6a9..40149edecbd5 100644
--- a/net/sched/sch_pie.c
+++ b/net/sched/sch_pie.c
@@ -90,7 +90,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
bool enqueue = false;
if (unlikely(qdisc_qlen(sch) >= sch->limit)) {
- q->stats.overlimit++;
+ WRITE_ONCE(q->stats.overlimit, q->stats.overlimit + 1);
goto out;
}
@@ -104,7 +104,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
/* If packet is ecn capable, mark it if drop probability
* is lower than 10%, else drop it.
*/
- q->stats.ecn_mark++;
+ WRITE_ONCE(q->stats.ecn_mark, q->stats.ecn_mark + 1);
enqueue = true;
}
@@ -114,15 +114,15 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
if (!q->params.dq_rate_estimator)
pie_set_enqueue_time(skb);
- q->stats.packets_in++;
+ WRITE_ONCE(q->stats.packets_in, q->stats.packets_in + 1);
if (qdisc_qlen(sch) > q->stats.maxq)
- q->stats.maxq = qdisc_qlen(sch);
+ WRITE_ONCE(q->stats.maxq, qdisc_qlen(sch));
return qdisc_enqueue_tail(skb, sch);
}
out:
- q->stats.dropped++;
+ WRITE_ONCE(q->stats.dropped, q->stats.dropped + 1);
q->vars.accu_prob = 0;
return qdisc_drop_reason(skb, sch, to_free, reason);
}
@@ -219,16 +219,14 @@ void pie_process_dequeue(struct sk_buff *skb, struct pie_params *params,
* packet timestamp.
*/
if (!params->dq_rate_estimator) {
- vars->qdelay = now - pie_get_enqueue_time(skb);
+ WRITE_ONCE(vars->qdelay,
+ backlog ? now - pie_get_enqueue_time(skb) : 0);
if (vars->dq_tstamp != DTIME_INVALID)
dtime = now - vars->dq_tstamp;
vars->dq_tstamp = now;
- if (backlog == 0)
- vars->qdelay = 0;
-
if (dtime == 0)
return;
@@ -267,11 +265,11 @@ void pie_process_dequeue(struct sk_buff *skb, struct pie_params *params,
count = count / dtime;
if (vars->avg_dq_rate == 0)
- vars->avg_dq_rate = count;
+ WRITE_ONCE(vars->avg_dq_rate, count);
else
- vars->avg_dq_rate =
+ WRITE_ONCE(vars->avg_dq_rate,
(vars->avg_dq_rate -
- (vars->avg_dq_rate >> 3)) + (count >> 3);
+ (vars->avg_dq_rate >> 3)) + (count >> 3));
/* If the queue has receded below the threshold, we hold
* on to the last drain rate calculated, else we reset
@@ -376,12 +374,12 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars,
if (qdelay > (PSCHED_NS2TICKS(250 * NSEC_PER_MSEC)))
delta += MAX_PROB / (100 / 2);
- vars->prob += delta;
+ WRITE_ONCE(vars->prob, vars->prob + delta);
if (delta > 0) {
/* prevent overflow */
if (vars->prob < oldprob) {
- vars->prob = MAX_PROB;
+ WRITE_ONCE(vars->prob, MAX_PROB);
/* Prevent normalization error. If probability is at
* maximum value already, we normalize it here, and
* skip the check to do a non-linear drop in the next
@@ -392,7 +390,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars,
} else {
/* prevent underflow */
if (vars->prob > oldprob)
- vars->prob = 0;
+ WRITE_ONCE(vars->prob, 0);
}
/* Non-linear drop in probability: Reduce drop probability quickly if
@@ -401,9 +399,9 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars,
if (qdelay == 0 && qdelay_old == 0 && update_prob)
/* Reduce drop probability to 98.4% */
- vars->prob -= vars->prob / 64;
+ WRITE_ONCE(vars->prob, vars->prob - vars->prob / 64);
- vars->qdelay = qdelay;
+ WRITE_ONCE(vars->qdelay, qdelay);
vars->backlog_old = backlog;
/* We restart the measurement cycle if the following conditions are met
@@ -501,22 +499,22 @@ static int pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
{
struct pie_sched_data *q = qdisc_priv(sch);
struct tc_pie_xstats st = {
- .prob = q->vars.prob << BITS_PER_BYTE,
- .delay = ((u32)PSCHED_TICKS2NS(q->vars.qdelay)) /
+ .prob = READ_ONCE(q->vars.prob) << BITS_PER_BYTE,
+ .delay = ((u32)PSCHED_TICKS2NS(READ_ONCE(q->vars.qdelay))) /
NSEC_PER_USEC,
- .packets_in = q->stats.packets_in,
- .overlimit = q->stats.overlimit,
- .maxq = q->stats.maxq,
- .dropped = q->stats.dropped,
- .ecn_mark = q->stats.ecn_mark,
+ .packets_in = READ_ONCE(q->stats.packets_in),
+ .overlimit = READ_ONCE(q->stats.overlimit),
+ .maxq = READ_ONCE(q->stats.maxq),
+ .dropped = READ_ONCE(q->stats.dropped),
+ .ecn_mark = READ_ONCE(q->stats.ecn_mark),
};
/* avg_dq_rate is only valid if dq_rate_estimator is enabled */
- st.dq_rate_estimating = q->params.dq_rate_estimator;
+ st.dq_rate_estimating = READ_ONCE(q->params.dq_rate_estimator);
/* unscale and return dq_rate in bytes per sec */
- if (q->params.dq_rate_estimator)
- st.avg_dq_rate = q->vars.avg_dq_rate *
+ if (st.dq_rate_estimating)
+ st.avg_dq_rate = READ_ONCE(q->vars.avg_dq_rate) *
(PSCHED_TICKS_PER_SEC) >> PIE_SCALE;
return gnet_stats_copy_app(d, &st, sizeof(st));
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index 68ee41ce78c5..86651a68d401 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -90,17 +90,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch,
case RED_PROB_MARK:
qdisc_qstats_overlimit(sch);
if (!red_use_ecn(q)) {
- q->stats.prob_drop++;
+ WRITE_ONCE(q->stats.prob_drop,
+ q->stats.prob_drop + 1);
goto congestion_drop;
}
if (INET_ECN_set_ce(skb)) {
- q->stats.prob_mark++;
+ WRITE_ONCE(q->stats.prob_mark,
+ q->stats.prob_mark + 1);
skb = tcf_qevent_handle(&q->qe_mark, sch, skb, to_free, &ret);
if (!skb)
return NET_XMIT_CN | ret;
} else if (!red_use_nodrop(q)) {
- q->stats.prob_drop++;
+ WRITE_ONCE(q->stats.prob_drop,
+ q->stats.prob_drop + 1);
goto congestion_drop;
}
@@ -111,17 +114,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch,
reason = SKB_DROP_REASON_QDISC_OVERLIMIT;
qdisc_qstats_overlimit(sch);
if (red_use_harddrop(q) || !red_use_ecn(q)) {
- q->stats.forced_drop++;
+ WRITE_ONCE(q->stats.forced_drop,
+ q->stats.forced_drop + 1);
goto congestion_drop;
}
if (INET_ECN_set_ce(skb)) {
- q->stats.forced_mark++;
+ WRITE_ONCE(q->stats.forced_mark,
+ q->stats.forced_mark + 1);
skb = tcf_qevent_handle(&q->qe_mark, sch, skb, to_free, &ret);
if (!skb)
return NET_XMIT_CN | ret;
} else if (!red_use_nodrop(q)) {
- q->stats.forced_drop++;
+ WRITE_ONCE(q->stats.forced_drop,
+ q->stats.forced_drop + 1);
goto congestion_drop;
}
@@ -135,7 +141,8 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch,
sch->qstats.backlog += len;
sch->q.qlen++;
} else if (net_xmit_drop_count(ret)) {
- q->stats.pdrop++;
+ WRITE_ONCE(q->stats.pdrop,
+ q->stats.pdrop + 1);
qdisc_qstats_drop(sch);
}
return ret;
@@ -463,9 +470,13 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_RED,
&hw_stats_request);
}
- st.early = q->stats.prob_drop + q->stats.forced_drop;
- st.pdrop = q->stats.pdrop;
- st.marked = q->stats.prob_mark + q->stats.forced_mark;
+ st.early = READ_ONCE(q->stats.prob_drop) +
+ READ_ONCE(q->stats.forced_drop);
+
+ st.pdrop = READ_ONCE(q->stats.pdrop);
+
+ st.marked = READ_ONCE(q->stats.prob_mark) +
+ READ_ONCE(q->stats.forced_mark);
return gnet_stats_copy_app(d, &st, sizeof(st));
}
diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c
index d2835f1168e1..00286c930b8d 100644
--- a/net/sched/sch_sfb.c
+++ b/net/sched/sch_sfb.c
@@ -130,7 +130,7 @@ static void increment_one_qlen(u32 sfbhash, u32 slot, struct sfb_sched_data *q)
sfbhash >>= SFB_BUCKET_SHIFT;
if (b[hash].qlen < 0xFFFF)
- b[hash].qlen++;
+ WRITE_ONCE(b[hash].qlen, b[hash].qlen + 1);
b += SFB_NUMBUCKETS; /* next level */
}
}
@@ -159,7 +159,7 @@ static void decrement_one_qlen(u32 sfbhash, u32 slot,
sfbhash >>= SFB_BUCKET_SHIFT;
if (b[hash].qlen > 0)
- b[hash].qlen--;
+ WRITE_ONCE(b[hash].qlen, b[hash].qlen - 1);
b += SFB_NUMBUCKETS; /* next level */
}
}
@@ -179,12 +179,12 @@ static void decrement_qlen(const struct sk_buff *skb, struct sfb_sched_data *q)
static void decrement_prob(struct sfb_bucket *b, struct sfb_sched_data *q)
{
- b->p_mark = prob_minus(b->p_mark, q->decrement);
+ WRITE_ONCE(b->p_mark, prob_minus(b->p_mark, q->decrement));
}
static void increment_prob(struct sfb_bucket *b, struct sfb_sched_data *q)
{
- b->p_mark = prob_plus(b->p_mark, q->increment);
+ WRITE_ONCE(b->p_mark, prob_plus(b->p_mark, q->increment));
}
static void sfb_zero_all_buckets(struct sfb_sched_data *q)
@@ -202,11 +202,14 @@ static u32 sfb_compute_qlen(u32 *prob_r, u32 *avgpm_r, const struct sfb_sched_da
const struct sfb_bucket *b = &q->bins[q->slot].bins[0][0];
for (i = 0; i < SFB_LEVELS * SFB_NUMBUCKETS; i++) {
- if (qlen < b->qlen)
- qlen = b->qlen;
- totalpm += b->p_mark;
- if (prob < b->p_mark)
- prob = b->p_mark;
+ u32 b_qlen = READ_ONCE(b->qlen);
+ u32 b_mark = READ_ONCE(b->p_mark);
+
+ if (qlen < b_qlen)
+ qlen = b_qlen;
+ totalpm += b_mark;
+ if (prob < b_mark)
+ prob = b_mark;
b++;
}
*prob_r = prob;
@@ -295,7 +298,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,
if (unlikely(sch->q.qlen >= q->limit)) {
qdisc_qstats_overlimit(sch);
- q->stats.queuedrop++;
+ WRITE_ONCE(q->stats.queuedrop,
+ q->stats.queuedrop + 1);
goto drop;
}
@@ -348,7 +352,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,
if (unlikely(minqlen >= q->max)) {
qdisc_qstats_overlimit(sch);
- q->stats.bucketdrop++;
+ WRITE_ONCE(q->stats.bucketdrop,
+ q->stats.bucketdrop + 1);
goto drop;
}
@@ -374,7 +379,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,
}
if (sfb_rate_limit(skb, q)) {
qdisc_qstats_overlimit(sch);
- q->stats.penaltydrop++;
+ WRITE_ONCE(q->stats.penaltydrop,
+ q->stats.penaltydrop + 1);
goto drop;
}
goto enqueue;
@@ -390,14 +396,17 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,
* In either case, we want to start dropping packets.
*/
if (r < (p_min - SFB_MAX_PROB / 2) * 2) {
- q->stats.earlydrop++;
+ WRITE_ONCE(q->stats.earlydrop,
+ q->stats.earlydrop + 1);
goto drop;
}
}
if (INET_ECN_set_ce(skb)) {
- q->stats.marked++;
+ WRITE_ONCE(q->stats.marked,
+ q->stats.marked + 1);
} else {
- q->stats.earlydrop++;
+ WRITE_ONCE(q->stats.earlydrop,
+ q->stats.earlydrop + 1);
goto drop;
}
}
@@ -410,7 +419,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,
sch->q.qlen++;
increment_qlen(&cb, q);
} else if (net_xmit_drop_count(ret)) {
- q->stats.childdrop++;
+ WRITE_ONCE(q->stats.childdrop,
+ q->stats.childdrop + 1);
qdisc_qstats_drop(sch);
}
return ret;
@@ -599,12 +609,12 @@ static int sfb_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
{
struct sfb_sched_data *q = qdisc_priv(sch);
struct tc_sfb_xstats st = {
- .earlydrop = q->stats.earlydrop,
- .penaltydrop = q->stats.penaltydrop,
- .bucketdrop = q->stats.bucketdrop,
- .queuedrop = q->stats.queuedrop,
- .childdrop = q->stats.childdrop,
- .marked = q->stats.marked,
+ .earlydrop = READ_ONCE(q->stats.earlydrop),
+ .penaltydrop = READ_ONCE(q->stats.penaltydrop),
+ .bucketdrop = READ_ONCE(q->stats.bucketdrop),
+ .queuedrop = READ_ONCE(q->stats.queuedrop),
+ .childdrop = READ_ONCE(q->stats.childdrop),
+ .marked = READ_ONCE(q->stats.marked),
};
st.maxqlen = sfb_compute_qlen(&st.maxprob, &st.avgprob, q);
diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c
index f721c03514f6..3c85ef1ef481 100644
--- a/net/sched/sch_taprio.c
+++ b/net/sched/sch_taprio.c
@@ -634,7 +634,7 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch,
queue = skb_get_queue_mapping(skb);
child = q->qdiscs[queue];
- if (unlikely(!child))
+ if (unlikely(child == &noop_qdisc))
return qdisc_drop(skb, sch, to_free);
if (taprio_skb_exceeds_queue_max_sdu(sch, skb)) {
@@ -717,7 +717,7 @@ static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq,
int len;
u8 tc;
- if (unlikely(!child))
+ if (unlikely(child == &noop_qdisc))
return NULL;
if (TXTIME_ASSIST_IS_ENABLED(q->flags))
@@ -972,11 +972,12 @@ static enum hrtimer_restart advance_sched(struct hrtimer *timer)
}
if (should_change_schedules(admin, oper, end_time)) {
- /* Set things so the next time this runs, the new
- * schedule runs.
- */
- end_time = sched_base_time(admin);
switch_schedules(q, &admin, &oper);
+ /* After changing schedules, the next entry is the first one
+ * in the new schedule, with a pre-calculated end_time.
+ */
+ next = list_first_entry(&oper->entries, struct sched_entry, list);
+ end_time = next->end_time;
}
next->end_time = end_time;
@@ -2183,6 +2184,9 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl,
if (!dev_queue)
return -EINVAL;
+ if (!new)
+ new = &noop_qdisc;
+
if (dev->flags & IFF_UP)
dev_deactivate(dev);
@@ -2196,14 +2200,14 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl,
*old = q->qdiscs[cl - 1];
if (FULL_OFFLOAD_IS_ENABLED(q->flags)) {
WARN_ON_ONCE(dev_graft_qdisc(dev_queue, new) != *old);
- if (new)
+ if (new != &noop_qdisc)
qdisc_refcount_inc(new);
- if (*old)
+ if (*old && *old != &noop_qdisc)
qdisc_put(*old);
}
q->qdiscs[cl - 1] = new;
- if (new)
+ if (new != &noop_qdisc)
new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
if (dev->flags & IFF_UP)
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c
index f5a7d5a38755..a024c0843247 100644
--- a/net/sctp/inqueue.c
+++ b/net/sctp/inqueue.c
@@ -201,6 +201,7 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
cb->chunk = head_cb->chunk;
cb->af = head_cb->af;
+ cb->encap_port = head_cb->encap_port;
}
}
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 53a5c027f8e3..cd15b695607e 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -261,9 +261,11 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *t)
skb_set_inner_ipproto(skb, IPPROTO_SCTP);
label = ip6_make_flowlabel(sock_net(sk), skb, fl6->flowlabel, true, fl6);
+ local_bh_disable();
udp_tunnel6_xmit_skb(dst, sk, skb, NULL, &fl6->saddr, &fl6->daddr,
tclass, ip6_dst_hoplimit(dst), label,
sctp_sk(sk)->udp_port, t->encap_port, false, 0);
+ local_bh_enable();
return 0;
}
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 828a59b8e7bf..5800e7ee7ea0 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -1070,10 +1070,12 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, struct sctp_transport *t)
skb_reset_inner_mac_header(skb);
skb_reset_inner_transport_header(skb);
skb_set_inner_ipproto(skb, IPPROTO_SCTP);
+ local_bh_disable();
udp_tunnel_xmit_skb(dst_rtable(dst), sk, skb, fl4->saddr,
fl4->daddr, dscp, ip4_dst_hoplimit(dst), df,
sctp_sk(sk)->udp_port, t->encap_port, false, false,
0);
+ local_bh_enable();
return 0;
}
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 7b823d759141..8e89a870780c 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -1556,6 +1556,12 @@ static enum sctp_disposition sctp_sf_do_unexpected_init(
/* Tag the variable length parameters. */
chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(struct sctp_inithdr));
+ if (asoc->state >= SCTP_STATE_ESTABLISHED) {
+ /* Discard INIT matching peer vtag after handshake completion (stale INIT). */
+ if (ntohl(chunk->subh.init_hdr->init_tag) == asoc->peer.i.init_tag)
+ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+ }
+
/* Verify the INIT chunk before processing it. */
err_chunk = NULL;
if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type,
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 48759da0a026..aeffa10ff2d3 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -4864,8 +4864,9 @@ static struct sock *sctp_clone_sock(struct sock *sk,
if (!newsk)
return ERR_PTR(err);
- /* sk_clone() sets refcnt to 2 */
+ /* sk_clone() sets refcnt to 2 and increments sockets_allocated */
sock_put(newsk);
+ sk_sockets_allocated_dec(newsk);
newinet = inet_sk(newsk);
newsp = sctp_sk(newsk);
@@ -7042,7 +7043,7 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
/* See if the user provided enough room for all the data */
num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr);
- if (len < num_chunks)
+ if (len < sizeof(struct sctp_authchunks) + num_chunks)
return -EINVAL;
if (copy_to_user(to, ch->chunks, num_chunks))
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index 9b623849723e..f2d72181a6fe 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -414,7 +414,6 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
struct ib_qp_init_attr qp_attr;
struct ib_device *dev;
int ret = 0;
- RPC_IFDEBUG(struct sockaddr *sap);
listen_rdma = container_of(xprt, struct svcxprt_rdma, sc_xprt);
clear_bit(XPT_CONN, &xprt->xpt_flags);
@@ -560,18 +559,20 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
goto errout;
}
-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
- dprintk("svcrdma: new connection accepted on device %s:\n", dev->name);
- sap = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.src_addr;
- dprintk(" local address : %pIS:%u\n", sap, rpc_get_port(sap));
- sap = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.dst_addr;
- dprintk(" remote address : %pIS:%u\n", sap, rpc_get_port(sap));
- dprintk(" max_sge : %d\n", newxprt->sc_max_send_sges);
- dprintk(" sq_depth : %d\n", newxprt->sc_sq_depth);
- dprintk(" rdma_rw_ctxs : %d\n", ctxts);
- dprintk(" max_requests : %d\n", newxprt->sc_max_requests);
- dprintk(" ord : %d\n", conn_param.initiator_depth);
-#endif
+ if (IS_ENABLED(CONFIG_SUNRPC_DEBUG)) {
+ struct sockaddr *sap;
+
+ dprintk("svcrdma: new connection accepted on device %s:\n", dev->name);
+ sap = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.src_addr;
+ dprintk(" local address : %pIS:%u\n", sap, rpc_get_port(sap));
+ sap = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.dst_addr;
+ dprintk(" remote address : %pIS:%u\n", sap, rpc_get_port(sap));
+ dprintk(" max_sge : %d\n", newxprt->sc_max_send_sges);
+ dprintk(" sq_depth : %d\n", newxprt->sc_sq_depth);
+ dprintk(" rdma_rw_ctxs : %d\n", ctxts);
+ dprintk(" max_requests : %d\n", newxprt->sc_max_requests);
+ dprintk(" ord : %d\n", conn_param.initiator_depth);
+ }
return &newxprt->sc_xprt;
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index 76284fc538eb..b0bba0feef56 100644
--- a/net/tipc/msg.c
+++ b/net/tipc/msg.c
@@ -177,8 +177,20 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
if (fragid == LAST_FRAGMENT) {
TIPC_SKB_CB(head)->validated = 0;
- if (unlikely(!tipc_msg_validate(&head)))
+
+ /* If the reassembled skb has been freed in
+ * tipc_msg_validate() because of an invalid truesize,
+ * then head will point to a newly allocated reassembled
+ * skb, while *headbuf points to freed reassembled skb.
+ * In such cases, correct *headbuf for freeing the newly
+ * allocated reassembled skb later.
+ */
+ if (unlikely(!tipc_msg_validate(&head))) {
+ if (head != *headbuf)
+ *headbuf = head;
goto err;
+ }
+
*buf = head;
TIPC_SKB_CB(head)->tail = NULL;
*headbuf = NULL;
diff --git a/net/tls/tls.h b/net/tls/tls.h
index 2f86baeb71fc..a1d8467bece3 100644
--- a/net/tls/tls.h
+++ b/net/tls/tls.h
@@ -188,6 +188,7 @@ int tls_strp_dev_init(void);
void tls_strp_dev_exit(void);
void tls_strp_done(struct tls_strparser *strp);
+void __tls_strp_done(struct tls_strparser *strp);
void tls_strp_stop(struct tls_strparser *strp);
int tls_strp_init(struct tls_strparser *strp, struct sock *sk);
void tls_strp_data_ready(struct tls_strparser *strp);
diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c
index 98e12f0ff57e..c72e88317627 100644
--- a/net/tls/tls_strp.c
+++ b/net/tls/tls_strp.c
@@ -624,6 +624,12 @@ void tls_strp_done(struct tls_strparser *strp)
WARN_ON(!strp->stopped);
cancel_work_sync(&strp->work);
+ __tls_strp_done(strp);
+}
+
+/* For setup error paths where the strparser was initialized but never armed. */
+void __tls_strp_done(struct tls_strparser *strp)
+{
tls_strp_anchor_free(strp);
}
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
index 83e78a3d1e65..23a31646d038 100644
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -2625,8 +2625,12 @@ void tls_sw_free_ctx_rx(struct tls_context *tls_ctx)
void tls_sw_free_resources_rx(struct sock *sk)
{
struct tls_context *tls_ctx = tls_get_ctx(sk);
+ struct tls_sw_context_rx *ctx;
+
+ ctx = tls_sw_ctx_rx(tls_ctx);
tls_sw_release_resources_rx(sk);
+ __tls_strp_done(&ctx->strp);
tls_sw_free_ctx_rx(tls_ctx);
}
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 09d43b4813b1..001f6602a665 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1964,16 +1964,19 @@ static void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb)
static void unix_destruct_scm(struct sk_buff *skb)
{
- struct scm_cookie scm;
+ struct scm_cookie scm = {};
+
+ swap(scm.pid, UNIXCB(skb).pid);
- memset(&scm, 0, sizeof(scm));
- scm.pid = UNIXCB(skb).pid;
if (UNIXCB(skb).fp)
unix_detach_fds(&scm, skb);
- /* Alas, it calls VFS */
- /* So fscking what? fput() had been SMP-safe since the last Summer */
scm_destroy(&scm);
+}
+
+static void unix_wfree(struct sk_buff *skb)
+{
+ unix_destruct_scm(skb);
sock_wfree(skb);
}
@@ -1989,7 +1992,7 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
if (scm->fp && send_fds)
err = unix_attach_fds(scm, skb);
- skb->destructor = unix_destruct_scm;
+ skb->destructor = unix_wfree;
return err;
}
@@ -2066,6 +2069,13 @@ static void scm_stat_del(struct sock *sk, struct sk_buff *skb)
}
}
+static void unix_orphan_scm(struct sock *sk, struct sk_buff *skb)
+{
+ scm_stat_del(sk, skb);
+ unix_destruct_scm(skb);
+ skb->destructor = sock_wfree;
+}
+
/*
* Send AF_UNIX data.
*/
@@ -2679,10 +2689,16 @@ static int unix_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
int err;
mutex_lock(&u->iolock);
+
skb = skb_recv_datagram(sk, MSG_DONTWAIT, &err);
- mutex_unlock(&u->iolock);
- if (!skb)
+ if (!skb) {
+ mutex_unlock(&u->iolock);
return err;
+ }
+
+ unix_orphan_scm(sk, skb);
+
+ mutex_unlock(&u->iolock);
return recv_actor(sk, skb);
}
@@ -2882,6 +2898,9 @@ static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
#endif
spin_unlock(&queue->lock);
+
+ unix_orphan_scm(sk, skb);
+
mutex_unlock(&u->iolock);
return recv_actor(sk, skb);
@@ -3734,15 +3753,15 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v)
struct bpf_prog *prog;
struct sock *sk = v;
uid_t uid;
- bool slow;
int ret;
if (v == SEQ_START_TOKEN)
return 0;
- slow = lock_sock_fast(sk);
+ lock_sock(sk);
+ unix_state_lock(sk);
- if (unlikely(sk_unhashed(sk))) {
+ if (unlikely(sock_flag(sk, SOCK_DEAD))) {
ret = SEQ_SKIP;
goto unlock;
}
@@ -3752,7 +3771,8 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v)
prog = bpf_iter_get_info(&meta, false);
ret = unix_prog_seq_show(prog, &meta, v, uid);
unlock:
- unlock_sock_fast(sk, slow);
+ unix_state_unlock(sk);
+ release_sock(sk);
return ret;
}
diff --git a/net/unix/unix_bpf.c b/net/unix/unix_bpf.c
index e0d30d6d22ac..57f3124c9d8d 100644
--- a/net/unix/unix_bpf.c
+++ b/net/unix/unix_bpf.c
@@ -185,6 +185,9 @@ int unix_stream_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool r
*/
if (!psock->sk_pair) {
sk_pair = unix_peer(sk);
+ if (unlikely(!sk_pair))
+ return -EINVAL;
+
sock_hold(sk_pair);
psock->sk_pair = sk_pair;
}
diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
index 6547e199ea5b..0d0265f770ad 100644
--- a/net/vmw_vsock/virtio_transport_common.c
+++ b/net/vmw_vsock/virtio_transport_common.c
@@ -75,6 +75,7 @@ static bool virtio_transport_can_zcopy(const struct virtio_transport *t_ops,
static int virtio_transport_init_zcopy_skb(struct vsock_sock *vsk,
struct sk_buff *skb,
struct msghdr *msg,
+ size_t pkt_len,
bool zerocopy)
{
struct ubuf_info *uarg;
@@ -83,12 +84,10 @@ static int virtio_transport_init_zcopy_skb(struct vsock_sock *vsk,
uarg = msg->msg_ubuf;
net_zcopy_get(uarg);
} else {
- struct iov_iter *iter = &msg->msg_iter;
struct ubuf_info_msgzc *uarg_zc;
uarg = msg_zerocopy_realloc(sk_vsock(vsk),
- iter->count,
- NULL, false);
+ pkt_len, NULL, false);
if (!uarg)
return -1;
@@ -385,11 +384,17 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
* each iteration. If this is last skb for this buffer
* and MSG_ZEROCOPY mode is in use - we must allocate
* completion for the current syscall.
+ *
+ * Pass pkt_len because msg iter is already consumed
+ * by virtio_transport_fill_skb(), so iter->count
+ * can not be used for RLIMIT_MEMLOCK pinned-pages
+ * accounting done by msg_zerocopy_realloc().
*/
if (info->msg && info->msg->msg_flags & MSG_ZEROCOPY &&
skb_len == rest_len && info->op == VIRTIO_VSOCK_OP_RW) {
if (virtio_transport_init_zcopy_skb(vsk, skb,
info->msg,
+ pkt_len,
can_zcopy)) {
kfree_skb(skb);
ret = -ENOMEM;
diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs
index f5adee48d40c..d8d26870bea2 100644
--- a/rust/kernel/cpufreq.rs
+++ b/rust/kernel/cpufreq.rs
@@ -1257,18 +1257,17 @@ impl<T: Driver> Registration<T> {
/// # Safety
///
/// - This function may only be called from the cpufreq C infrastructure.
+ /// - The pointer arguments must be valid pointers.
unsafe extern "C" fn adjust_perf_callback(
- cpu: c_uint,
+ ptr: *mut bindings::cpufreq_policy,
min_perf: c_ulong,
target_perf: c_ulong,
capacity: c_ulong,
) {
- // SAFETY: The C API guarantees that `cpu` refers to a valid CPU number.
- let cpu_id = unsafe { CpuId::from_u32_unchecked(cpu) };
-
- if let Ok(mut policy) = PolicyCpu::from_cpu(cpu_id) {
- T::adjust_perf(&mut policy, min_perf, target_perf, capacity);
- }
+ // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the
+ // lifetime of `policy`.
+ let policy = unsafe { Policy::from_raw_mut(ptr) };
+ T::adjust_perf(policy, min_perf, target_perf, capacity);
}
/// Driver's `get_intermediate` callback.
diff --git a/rust/kernel/sync/atomic.rs b/rust/kernel/sync/atomic.rs
index 4aebeacb961a..296b25e83bbb 100644
--- a/rust/kernel/sync/atomic.rs
+++ b/rust/kernel/sync/atomic.rs
@@ -204,10 +204,7 @@ pub const fn new(v: T) -> Self {
/// // no data race.
/// unsafe { Atomic::from_ptr(foo_a_ptr) }.store(2, Release);
/// ```
- pub unsafe fn from_ptr<'a>(ptr: *mut T) -> &'a Self
- where
- T: Sync,
- {
+ pub unsafe fn from_ptr<'a>(ptr: *mut T) -> &'a Self {
// CAST: `T` and `Atomic<T>` have the same size, alignment and bit validity.
// SAFETY: Per function safety requirement, `ptr` is a valid pointer and the object will
// live long enough. It's safe to return a `&Atomic<T>` because function safety requirement
diff --git a/scripts/gdb/linux/timerlist.py b/scripts/gdb/linux/timerlist.py
index ccc24d30de80..9fb3436a217c 100644
--- a/scripts/gdb/linux/timerlist.py
+++ b/scripts/gdb/linux/timerlist.py
@@ -20,7 +20,7 @@ def ktime_get():
We can't read the hardware timer itself to add any nanoseconds
that need to be added since we last stored the time in the
timekeeper. But this is probably good enough for debug purposes."""
- tk_core = gdb.parse_and_eval("&tk_core")
+ tk_core = gdb.parse_and_eval("&timekeeper_data[TIMEKEEPER_CORE]")
return tk_core['timekeeper']['tkr_mono']['base']
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
index 3627ca227e5a..ba1defc61652 100755
--- a/scripts/package/builddeb
+++ b/scripts/package/builddeb
@@ -139,7 +139,13 @@ install_kernel_headers () {
pdir=debian/$1
version=${1#linux-headers-}
- CC="${DEB_HOST_GNU_TYPE}-gcc" "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}"
+ # Override $CC only for cross-compiles, to not unnecessarily rebuild
+ # scripts/ including plugins, which may lead to a full kernel rebuild.
+ if [ -n "${CROSS_COMPILE}" ]; then
+ CC="${DEB_HOST_GNU_TYPE}-gcc" "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}"
+ else
+ "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}"
+ fi
mkdir -p $pdir/lib/modules/$version/
ln -s /usr/src/linux-headers-$version $pdir/lib/modules/$version/build
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index aff61643415d..85c433e39c00 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c
@@ -832,7 +832,7 @@ static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id,
}
}
if (!rc)
- crypto_shash_final(shash, digest);
+ rc = crypto_shash_final(shash, digest);
return rc;
}
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 012a58959ff0..f3c461ad7062 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -404,16 +404,24 @@ static int __init create_securityfs_measurement_lists(void)
char file_name[NAME_MAX + 1];
struct dentry *dentry;
- sprintf(file_name, "ascii_runtime_measurements_%s",
- hash_algo_name[algo]);
+ if (algo == HASH_ALGO__LAST)
+ sprintf(file_name, "ascii_runtime_measurements_tpm_alg_%x",
+ ima_tpm_chip->allocated_banks[i].alg_id);
+ else
+ sprintf(file_name, "ascii_runtime_measurements_%s",
+ hash_algo_name[algo]);
dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
ima_dir, (void *)(uintptr_t)i,
&ima_ascii_measurements_ops);
if (IS_ERR(dentry))
return PTR_ERR(dentry);
- sprintf(file_name, "binary_runtime_measurements_%s",
- hash_algo_name[algo]);
+ if (algo == HASH_ALGO__LAST)
+ sprintf(file_name, "binary_runtime_measurements_tpm_alg_%x",
+ ima_tpm_chip->allocated_banks[i].alg_id);
+ else
+ sprintf(file_name, "binary_runtime_measurements_%s",
+ hash_algo_name[algo]);
dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
ima_dir, (void *)(uintptr_t)i,
&ima_measurements_ops);
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index fdba6e4b25fd..5a0308eb4e31 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -41,13 +41,6 @@
#define COMPR_CODEC_CAPS_OVERFLOW
#endif
-/* TODO:
- * - add substream support for multiple devices in case of
- * SND_DYNAMIC_MINORS is not used
- * - Multiple node representation
- * driver should be able to register multiple nodes
- */
-
struct snd_compr_file {
unsigned long caps;
struct snd_compr_stream stream;
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 93436db24710..8d05fe0d263b 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -216,9 +216,16 @@ static int snd_find_free_minor(int type, struct snd_card *card, int dev)
case SNDRV_DEVICE_TYPE_RAWMIDI:
case SNDRV_DEVICE_TYPE_PCM_PLAYBACK:
case SNDRV_DEVICE_TYPE_PCM_CAPTURE:
+ if (snd_BUG_ON(!card))
+ return -EINVAL;
+ minor = SNDRV_MINOR(card->number, type + dev);
+ break;
case SNDRV_DEVICE_TYPE_COMPRESS:
if (snd_BUG_ON(!card))
return -EINVAL;
+ if (dev < 0 ||
+ dev >= SNDRV_MINOR_HWDEP - SNDRV_MINOR_COMPRESS)
+ return -EINVAL;
minor = SNDRV_MINOR(card->number, type + dev);
break;
default:
diff --git a/sound/hda/codecs/cmedia.c b/sound/hda/codecs/cmedia.c
index e6e12c01339f..88dd80d987d4 100644
--- a/sound/hda/codecs/cmedia.c
+++ b/sound/hda/codecs/cmedia.c
@@ -39,13 +39,6 @@ static int cmedia_probe(struct hda_codec *codec, const struct hda_device_id *id)
spec->out_vol_mask = (1ULL << 0x10);
}
- err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
- if (err < 0)
- goto error;
- err = snd_hda_gen_parse_auto_config(codec, cfg);
- if (err < 0)
- goto error;
-
err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
if (err < 0)
goto error;
diff --git a/sound/hda/codecs/conexant.c b/sound/hda/codecs/conexant.c
index aa726eb323eb..a7689f9ef967 100644
--- a/sound/hda/codecs/conexant.c
+++ b/sound/hda/codecs/conexant.c
@@ -1183,6 +1183,7 @@ static void add_cx5051_fake_mutes(struct hda_codec *codec)
static int cx_probe(struct hda_codec *codec, const struct hda_device_id *id)
{
struct conexant_spec *spec;
+ struct hda_jack_callback *callback;
int err;
codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name);
@@ -1198,7 +1199,12 @@ static int cx_probe(struct hda_codec *codec, const struct hda_device_id *id)
case 0x14f11f86:
case 0x14f11f87:
spec->is_cx11880_sn6140 = true;
- snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref);
+ callback = snd_hda_jack_detect_enable_callback(codec, 0x19,
+ cx_update_headset_mic_vref);
+ if (IS_ERR(callback)) {
+ err = PTR_ERR(callback);
+ goto error;
+ }
break;
}
diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c
index ded6e78142a0..8f7d8337b4bc 100644
--- a/sound/hda/codecs/realtek/alc269.c
+++ b/sound/hda/codecs/realtek/alc269.c
@@ -2296,9 +2296,9 @@ static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec,
struct alc_spec *spec = codec->spec;
spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
alc255_set_default_jack_type(codec);
- }
- else
+ } else {
alc_fixup_headset_mode(codec, fix, action);
+ }
}
static void alc288_update_headset_jack_cb(struct hda_codec *codec,
@@ -3674,22 +3674,11 @@ static void alc287_alc1318_playback_pcm_hook(struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream,
int action)
{
- static const struct coef_fw dis_coefs[] = {
- WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC203),
- WRITE_COEF(0x28, 0x0004), WRITE_COEF(0x29, 0xb023),
- }; /* Disable AMP silence detection */
- static const struct coef_fw en_coefs[] = {
- WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC203),
- WRITE_COEF(0x28, 0x0084), WRITE_COEF(0x29, 0xb023),
- }; /* Enable AMP silence detection */
-
switch (action) {
case HDA_GEN_PCM_ACT_OPEN:
- alc_process_coef_fw(codec, dis_coefs);
alc_write_coefex_idx(codec, 0x5a, 0x00, 0x954f); /* write gpio3 to high */
break;
case HDA_GEN_PCM_ACT_CLOSE:
- alc_process_coef_fw(codec, en_coefs);
alc_write_coefex_idx(codec, 0x5a, 0x00, 0x554f); /* write gpio3 as default value */
break;
}
@@ -3712,10 +3701,15 @@ static void alc287_fixup_lenovo_thinkpad_with_alc1318(struct hda_codec *codec,
WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC301),
WRITE_COEF(0x28, 0x0001), WRITE_COEF(0x29, 0xb023),
};
+ static const struct coef_fw dis_coefs[] = {
+ WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC203),
+ WRITE_COEF(0x28, 0x0004), WRITE_COEF(0x29, 0xb023),
+ }; /* Disable AMP silence detection */
if (action != HDA_FIXUP_ACT_PRE_PROBE)
return;
alc_update_coef_idx(codec, 0x10, 1<<11, 1<<11);
+ alc_process_coef_fw(codec, dis_coefs);
alc_process_coef_fw(codec, coefs);
spec->power_hook = alc287_s4_power_gpio3_default;
spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook;
@@ -6657,10 +6651,10 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc288_fixup_surface_swap_dacs,
},
- [ALC233_FIXUP_LENOVO_GPIO2_MIC_HOTKEY] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc233_fixup_lenovo_gpio2_mic_hotkey,
- },
+ [ALC233_FIXUP_LENOVO_GPIO2_MIC_HOTKEY] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc233_fixup_lenovo_gpio2_mic_hotkey,
+ },
[ALC245_FIXUP_BASS_HP_DAC] = {
.type = HDA_FIXUP_FUNC,
/* Borrow the DAC routing selected for those Thinkpads */
@@ -7152,6 +7146,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8ca4, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8ca7, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8caf, "HP Elite mt645 G8 Mobile Thin Client", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8cbc, "HP Pavilion Laptop 16-ag0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS),
SND_PCI_QUIRK(0x103c, 0x8cbd, "HP Pavilion Aero Laptop 13-bg0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS),
SND_PCI_QUIRK(0x103c, 0x8cdd, "HP Spectre", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
SND_PCI_QUIRK(0x103c, 0x8cde, "HP OmniBook Ultra Flip Laptop 14t", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
@@ -7453,6 +7448,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x144d, 0xc870, "Samsung Galaxy Book2 Pro (NP950XED)", ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS),
SND_PCI_QUIRK(0x144d, 0xc872, "Samsung Galaxy Book2 Pro (NP950XEE)", ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS),
SND_PCI_QUIRK(0x144d, 0xc886, "Samsung Galaxy Book3 Pro (NP964XFG)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
+ SND_PCI_QUIRK(0x144d, 0xc902, "Samsung Galaxy Book5 360 (NP750QHA)", ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
SND_PCI_QUIRK(0x144d, 0xc1ca, "Samsung Galaxy Book3 Pro 360 (NP960QFG)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
SND_PCI_QUIRK(0x144d, 0xc1cb, "Samsung Galaxy Book3 Pro 360 (NP965QFG)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
SND_PCI_QUIRK(0x144d, 0xc1cc, "Samsung Galaxy Book3 Ultra (NT960XFH)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.c b/sound/hda/codecs/side-codecs/cs35l56_hda.c
index dc25960a4f23..4c8d01799931 100644
--- a/sound/hda/codecs/side-codecs/cs35l56_hda.c
+++ b/sound/hda/codecs/side-codecs/cs35l56_hda.c
@@ -976,6 +976,7 @@ static int cs35l56_hda_system_resume(struct device *dev)
static int cs35l56_hda_fixup_yoga9(struct cs35l56_hda *cs35l56, int *bus_addr)
{
/* The cirrus,dev-index property has the wrong values */
+ cs35l56->num_amps = 2;
switch (*bus_addr) {
case 0x30:
cs35l56->index = 1;
@@ -1025,7 +1026,6 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
char hid_string[8];
struct acpi_device *adev;
const char *property, *sub;
- size_t nval;
int i, ret;
/*
@@ -1061,13 +1061,14 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
ret = -EINVAL;
goto err;
}
- nval = ret;
+ cs35l56->num_amps = ret;
- ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval);
+ ret = device_property_read_u32_array(cs35l56->base.dev, property, values,
+ cs35l56->num_amps);
if (ret)
goto err;
- for (i = 0; i < nval; i++) {
+ for (i = 0; i < cs35l56->num_amps; i++) {
if (values[i] == id) {
cs35l56->index = i;
break;
@@ -1090,7 +1091,8 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
"Read ACPI _SUB failed(%ld): fallback to generic firmware\n",
PTR_ERR(sub));
} else {
- ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index, nval, -1);
+ ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index,
+ cs35l56->num_amps, -1);
if (ret == -ENOENT) {
cs35l56->system_name = sub;
} else if (ret >= 0) {
diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.h b/sound/hda/codecs/side-codecs/cs35l56_hda.h
index cb4b5e7356a3..3705af7c186b 100644
--- a/sound/hda/codecs/side-codecs/cs35l56_hda.h
+++ b/sound/hda/codecs/side-codecs/cs35l56_hda.h
@@ -26,6 +26,7 @@ struct cs35l56_hda {
struct work_struct dsp_work;
int index;
+ int num_amps;
const char *system_name;
const char *amp_name;
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
index f860e0eb7602..6c736b17c983 100644
--- a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
+++ b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
@@ -132,10 +132,18 @@ static int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tas_priv,
int ret, val;
/*
- * In our TAS2781 SPI mode, read/write was masked in last bit of
- * address, it cause regmap_update_bits() not work as expected.
+ * In TAS2781 SPI mode, when accessing non-book-zero or page numbers
+ * greater than 1 in book 0, an additional byte must be read. The
+ * first byte in such cases is a dummy byte and should be ignored.
*/
- ret = tasdevice_dev_read(tas_priv, chn, reg, &val);
+ if ((TASDEVICE_BOOK_ID(reg) > 0) || (TASDEVICE_PAGE_ID(reg) > 1)) {
+ unsigned char buf[2];
+
+ ret = tasdevice_dev_bulk_read(tas_priv, chn, reg, buf, 2);
+ val = buf[1];
+ } else {
+ ret = tasdevice_dev_read(tas_priv, chn, reg, &val);
+ }
if (ret < 0) {
dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
return ret;
diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c
index 09b1329bb8f3..5123df32ad89 100644
--- a/sound/hda/common/codec.c
+++ b/sound/hda/common/codec.c
@@ -2529,7 +2529,10 @@ EXPORT_SYMBOL_GPL(snd_hda_spdif_ctls_assign);
static int spdif_share_sw_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol);
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct hda_multi_out *mout = (void *)kcontrol->private_value;
+
+ guard(mutex)(&codec->spdif_mutex);
ucontrol->value.integer.value[0] = mout->share_spdif;
return 0;
}
@@ -2537,9 +2540,15 @@ static int spdif_share_sw_get(struct snd_kcontrol *kcontrol,
static int spdif_share_sw_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol);
- mout->share_spdif = !!ucontrol->value.integer.value[0];
- return 0;
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct hda_multi_out *mout = (void *)kcontrol->private_value;
+ bool val = !!ucontrol->value.integer.value[0];
+ int change;
+
+ guard(mutex)(&codec->spdif_mutex);
+ change = mout->share_spdif != val;
+ mout->share_spdif = val;
+ return change;
}
static const struct snd_kcontrol_new spdif_share_sw = {
@@ -2550,6 +2559,14 @@ static const struct snd_kcontrol_new spdif_share_sw = {
.put = spdif_share_sw_put,
};
+static void notify_spdif_share_sw(struct hda_codec *codec,
+ struct hda_multi_out *mout)
+{
+ if (mout->share_spdif_kctl)
+ snd_ctl_notify_one(codec->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ mout->share_spdif_kctl, 0);
+}
+
/**
* snd_hda_create_spdif_share_sw - create Default PCM switch
* @codec: the HDA codec
@@ -2559,15 +2576,24 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
struct hda_multi_out *mout)
{
struct snd_kcontrol *kctl;
+ int err;
if (!mout->dig_out_nid)
return 0;
- kctl = snd_ctl_new1(&spdif_share_sw, mout);
+ kctl = snd_ctl_new1(&spdif_share_sw, codec);
if (!kctl)
return -ENOMEM;
- /* ATTENTION: here mout is passed as private_data, instead of codec */
- return snd_hda_ctl_add(codec, mout->dig_out_nid, kctl);
+ /* snd_ctl_new1() stores @codec in private_data; stash @mout in
+ * private_value for the share-switch callbacks and cache the
+ * assigned control for forced-disable notifications.
+ */
+ kctl->private_value = (unsigned long)mout;
+ err = snd_hda_ctl_add(codec, mout->dig_out_nid, kctl);
+ if (err < 0)
+ return err;
+ mout->share_spdif_kctl = kctl;
+ return 0;
}
EXPORT_SYMBOL_GPL(snd_hda_create_spdif_share_sw);
@@ -3701,6 +3727,8 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec,
struct hda_pcm_stream *hinfo)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+ bool notify_share_sw = false;
+
runtime->hw.channels_max = mout->max_channels;
if (mout->dig_out_nid) {
if (!mout->analog_rates) {
@@ -3729,10 +3757,12 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec,
hinfo->maxbps = mout->spdif_maxbps;
} else {
mout->share_spdif = 0;
- /* FIXME: need notify? */
+ notify_share_sw = true;
}
}
}
+ if (notify_share_sw)
+ notify_spdif_share_sw(codec, mout);
return snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS, 2);
}
diff --git a/sound/hda/common/hda_local.h b/sound/hda/common/hda_local.h
index ab423f1cef54..98b2c4acebc2 100644
--- a/sound/hda/common/hda_local.h
+++ b/sound/hda/common/hda_local.h
@@ -221,6 +221,7 @@ struct hda_multi_out {
unsigned int spdif_rates;
unsigned int spdif_maxbps;
u64 spdif_formats;
+ struct snd_kcontrol *share_spdif_kctl; /* cached shared SPDIF switch */
};
int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c
index 6d618cc2ba45..9949e06403f6 100644
--- a/sound/isa/sc6000.c
+++ b/sound/isa/sc6000.c
@@ -100,6 +100,15 @@ MODULE_PARM_DESC(joystick, "Enable gameport.");
#define PFX "sc6000: "
#define DRV_NAME "SC-6000"
+struct snd_sc6000 {
+ char __iomem *vport;
+ char __iomem *vmss_port;
+ u8 mss_config;
+ u8 config;
+ u8 hw_cfg[2];
+ bool old_dsp;
+};
+
/* hardware dependent functions */
/*
@@ -267,7 +276,7 @@ static int sc6000_dsp_reset(char __iomem *vport)
/* detection and initialization */
static int sc6000_hw_cfg_write(struct device *devptr,
- char __iomem *vport, const int *cfg)
+ char __iomem *vport, const u8 *cfg)
{
if (sc6000_write(devptr, vport, COMMAND_6C) < 0) {
dev_warn(devptr, "CMD 0x%x: failed!\n", COMMAND_6C);
@@ -353,8 +362,7 @@ static int sc6000_init_mss(struct device *devptr,
return 0;
}
-static void sc6000_hw_cfg_encode(struct device *devptr,
- char __iomem *vport, int *cfg,
+static void sc6000_hw_cfg_encode(struct device *devptr, u8 *cfg,
long xport, long xmpu,
long xmss_port, int joystick)
{
@@ -376,27 +384,83 @@ static void sc6000_hw_cfg_encode(struct device *devptr,
dev_dbg(devptr, "hw cfg %x, %x\n", cfg[0], cfg[1]);
}
-static int sc6000_init_board(struct device *devptr,
- char __iomem *vport,
- char __iomem *vmss_port, int dev)
+static void sc6000_prepare_board(struct device *devptr,
+ struct snd_sc6000 *sc6000,
+ unsigned int dev, int xirq, int xdma)
+{
+ sc6000->mss_config = sc6000_irq_to_softcfg(xirq) |
+ sc6000_dma_to_softcfg(xdma);
+ sc6000->config = sc6000->mss_config |
+ sc6000_mpu_irq_to_softcfg(mpu_irq[dev]);
+ sc6000_hw_cfg_encode(devptr, sc6000->hw_cfg, port[dev], mpu_port[dev],
+ mss_port[dev], joystick[dev]);
+}
+
+static void sc6000_detect_old_dsp(struct device *devptr,
+ struct snd_sc6000 *sc6000)
+{
+ sc6000_write(devptr, sc6000->vport, COMMAND_5C);
+ sc6000->old_dsp = sc6000_read(sc6000->vport) < 0;
+}
+
+static int sc6000_program_board(struct device *devptr,
+ struct snd_sc6000 *sc6000)
+{
+ int err;
+
+ if (!sc6000->old_dsp) {
+ if (sc6000_hw_cfg_write(devptr, sc6000->vport,
+ sc6000->hw_cfg) < 0) {
+ dev_err(devptr, "sc6000_hw_cfg_write: failed!\n");
+ return -EIO;
+ }
+ }
+
+ err = sc6000_setup_board(devptr, sc6000->vport, sc6000->config);
+ if (err < 0) {
+ dev_err(devptr, "sc6000_setup_board: failed!\n");
+ return -ENODEV;
+ }
+
+ sc6000_dsp_reset(sc6000->vport);
+
+ if (!sc6000->old_dsp) {
+ sc6000_write(devptr, sc6000->vport, COMMAND_60);
+ sc6000_write(devptr, sc6000->vport, 0x02);
+ sc6000_dsp_reset(sc6000->vport);
+ }
+
+ err = sc6000_setup_board(devptr, sc6000->vport, sc6000->config);
+ if (err < 0) {
+ dev_err(devptr, "sc6000_setup_board: failed!\n");
+ return -ENODEV;
+ }
+
+ err = sc6000_init_mss(devptr, sc6000->vport, sc6000->config,
+ sc6000->vmss_port, sc6000->mss_config);
+ if (err < 0) {
+ dev_err(devptr, "Cannot initialize Microsoft Sound System mode.\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int sc6000_init_board(struct device *devptr, struct snd_sc6000 *sc6000)
{
char answer[15];
char version[2];
- int mss_config = sc6000_irq_to_softcfg(irq[dev]) |
- sc6000_dma_to_softcfg(dma[dev]);
- int config = mss_config |
- sc6000_mpu_irq_to_softcfg(mpu_irq[dev]);
int err;
- int old = 0;
- err = sc6000_dsp_reset(vport);
+ err = sc6000_dsp_reset(sc6000->vport);
if (err < 0) {
dev_err(devptr, "sc6000_dsp_reset: failed!\n");
return err;
}
memset(answer, 0, sizeof(answer));
- err = sc6000_dsp_get_answer(devptr, vport, GET_DSP_COPYRIGHT, answer, 15);
+ err = sc6000_dsp_get_answer(devptr, sc6000->vport, GET_DSP_COPYRIGHT,
+ answer, 15);
if (err <= 0) {
dev_err(devptr, "sc6000_dsp_copyright: failed!\n");
return -ENODEV;
@@ -408,54 +472,17 @@ static int sc6000_init_board(struct device *devptr,
if (strncmp("SC-6000", answer, 7))
dev_warn(devptr, "Warning: non SC-6000 audio card!\n");
- if (sc6000_dsp_get_answer(devptr, vport, GET_DSP_VERSION, version, 2) < 2) {
+ if (sc6000_dsp_get_answer(devptr, sc6000->vport,
+ GET_DSP_VERSION, version, 2) < 2) {
dev_err(devptr, "sc6000_dsp_version: failed!\n");
return -ENODEV;
}
dev_info(devptr, "Detected model: %s, DSP version %d.%d\n",
answer, version[0], version[1]);
- /* set configuration */
- sc6000_write(devptr, vport, COMMAND_5C);
- if (sc6000_read(vport) < 0)
- old = 1;
-
- if (!old) {
- int cfg[2];
- sc6000_hw_cfg_encode(devptr,
- vport, &cfg[0], port[dev], mpu_port[dev],
- mss_port[dev], joystick[dev]);
- if (sc6000_hw_cfg_write(devptr, vport, cfg) < 0) {
- dev_err(devptr, "sc6000_hw_cfg_write: failed!\n");
- return -EIO;
- }
- }
- err = sc6000_setup_board(devptr, vport, config);
- if (err < 0) {
- dev_err(devptr, "sc6000_setup_board: failed!\n");
- return -ENODEV;
- }
-
- sc6000_dsp_reset(vport);
-
- if (!old) {
- sc6000_write(devptr, vport, COMMAND_60);
- sc6000_write(devptr, vport, 0x02);
- sc6000_dsp_reset(vport);
- }
+ sc6000_detect_old_dsp(devptr, sc6000);
- err = sc6000_setup_board(devptr, vport, config);
- if (err < 0) {
- dev_err(devptr, "sc6000_setup_board: failed!\n");
- return -ENODEV;
- }
- err = sc6000_init_mss(devptr, vport, config, vmss_port, mss_config);
- if (err < 0) {
- dev_err(devptr, "Cannot initialize Microsoft Sound System mode.\n");
- return -ENODEV;
- }
-
- return 0;
+ return sc6000_program_board(devptr, sc6000);
}
static int snd_sc6000_mixer(struct snd_wss *chip)
@@ -538,10 +565,10 @@ static int snd_sc6000_match(struct device *devptr, unsigned int dev)
static void snd_sc6000_free(struct snd_card *card)
{
- char __iomem *vport = (char __force __iomem *)card->private_data;
+ struct snd_sc6000 *sc6000 = card->private_data;
- if (vport)
- sc6000_setup_board(card->dev, vport, 0);
+ if (sc6000->vport)
+ sc6000_setup_board(card->dev, sc6000->vport, 0);
}
static int __snd_sc6000_probe(struct device *devptr, unsigned int dev)
@@ -552,15 +579,17 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev)
int xirq = irq[dev];
int xdma = dma[dev];
struct snd_card *card;
+ struct snd_sc6000 *sc6000;
struct snd_wss *chip;
struct snd_opl3 *opl3;
char __iomem *vport;
char __iomem *vmss_port;
err = snd_devm_card_new(devptr, index[dev], id[dev], THIS_MODULE,
- 0, &card);
+ sizeof(*sc6000), &card);
if (err < 0)
return err;
+ sc6000 = card->private_data;
if (xirq == SNDRV_AUTO_IRQ) {
xirq = snd_legacy_find_free_irq(possible_irqs);
@@ -587,7 +616,7 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev)
dev_err(devptr, "I/O port cannot be iomapped.\n");
return -EBUSY;
}
- card->private_data = (void __force *)vport;
+ sc6000->vport = vport;
/* to make it marked as used */
if (!devm_request_region(devptr, mss_port[dev], 4, DRV_NAME)) {
@@ -600,12 +629,15 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev)
dev_err(devptr, "MSS port I/O cannot be iomapped.\n");
return -EBUSY;
}
+ sc6000->vmss_port = vmss_port;
dev_dbg(devptr, "Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n",
port[dev], xirq, xdma,
mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]);
- err = sc6000_init_board(devptr, vport, vmss_port, dev);
+ sc6000_prepare_board(devptr, sc6000, dev, xirq, xdma);
+
+ err = sc6000_init_board(devptr, sc6000);
if (err < 0)
return err;
card->private_free = snd_sc6000_free;
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index c76a4bcc9645..6ad70aa0ea83 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -1252,7 +1252,7 @@ static const struct snd_soc_component_driver acp_asoc_platform = {
.pointer = acp_dma_pointer,
.delay = acp_dma_delay,
.prepare = acp_dma_prepare,
- .pcm_construct = acp_dma_new,
+ .pcm_new = acp_dma_new,
};
static int acp_audio_probe(struct platform_device *pdev)
diff --git a/sound/soc/amd/acp/acp-legacy-mach.c b/sound/soc/amd/acp/acp-legacy-mach.c
index a7a551366a40..235d6cc83fa9 100644
--- a/sound/soc/amd/acp/acp-legacy-mach.c
+++ b/sound/soc/amd/acp/acp-legacy-mach.c
@@ -174,7 +174,7 @@ static int acp_asoc_probe(struct platform_device *pdev)
acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev;
dmi_id = dmi_first_match(acp_quirk_table);
- if (dmi_id && dmi_id->driver_data)
+ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE)
acp_card_drvdata->tdm_mode = dmi_id->driver_data;
ret = acp_legacy_dai_links_create(card);
diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c
index 09f6c9a2c041..ef784cca13f2 100644
--- a/sound/soc/amd/acp/acp-mach-common.c
+++ b/sound/soc/amd/acp/acp-mach-common.c
@@ -20,6 +20,7 @@
#include <sound/soc.h>
#include <linux/input.h>
#include <linux/module.h>
+#include <linux/dmi.h>
#include "../../codecs/rt5682.h"
#include "../../codecs/rt1019.h"
@@ -37,15 +38,21 @@
#define NAU8821_FREQ_OUT 12288000
#define MAX98388_CODEC_DAI "max98388-aif1"
-#define TDM_MODE_ENABLE 1
-
const struct dmi_system_id acp_quirk_table[] = {
{
/* Google skyrim proto-0 */
.matches = {
DMI_EXACT_MATCH(DMI_PRODUCT_FAMILY, "Google_Skyrim"),
},
- .driver_data = (void *)TDM_MODE_ENABLE,
+ .driver_data = (void *)QUIRK_TDM_MODE_ENABLE,
+ },
+ {
+ /* Valve Steam Deck OLED */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Valve"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"),
+ },
+ .driver_data = (void *)QUIRK_REMAP_DMIC_BT,
},
{}
};
@@ -1401,6 +1408,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
struct snd_soc_dai_link *links;
struct device *dev = card->dev;
struct acp_card_drvdata *drv_data = card->drvdata;
+ const struct dmi_system_id *dmi_id = dmi_first_match(acp_quirk_table);
int i = 0, num_links = 0;
if (drv_data->hs_cpu_id)
@@ -1572,6 +1580,9 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
links[i].codecs = &snd_soc_dummy_dlc;
links[i].num_codecs = 1;
}
+
+ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT)
+ links[i].id = DMIC_BE_ID;
i++;
}
@@ -1587,6 +1598,11 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
links[i].capture_only = 1;
links[i].nonatomic = true;
links[i].no_pcm = 1;
+
+ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT) {
+ links[i].id = BT_BE_ID;
+ dev_dbg(dev, "quirk REMAP_DMIC_BT enabled\n");
+ }
}
card->dai_link = links;
diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h
index f94c30c20f20..7177d3fd9619 100644
--- a/sound/soc/amd/acp/acp-mach.h
+++ b/sound/soc/amd/acp/acp-mach.h
@@ -26,6 +26,10 @@
#define acp_get_drvdata(card) ((struct acp_card_drvdata *)(card)->drvdata)
+/* List of DMI quirks - check acp-mach-common.c for usage. */
+#define QUIRK_TDM_MODE_ENABLE 1
+#define QUIRK_REMAP_DMIC_BT 2
+
enum be_id {
HEADSET_BE_ID = 0,
AMP_BE_ID,
diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c
index 88613569fd64..6b1e18b31c1c 100644
--- a/sound/soc/amd/acp/acp-platform.c
+++ b/sound/soc/amd/acp/acp-platform.c
@@ -321,7 +321,7 @@ static const struct snd_soc_component_driver acp_pcm_component = {
.close = acp_dma_close,
.hw_params = acp_dma_hw_params,
.pointer = acp_dma_pointer,
- .pcm_construct = acp_dma_new,
+ .pcm_new = acp_dma_new,
.legacy_dai_naming = 1,
};
diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
index cd7b1acc7216..a9c8d9545281 100644
--- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c
+++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
@@ -551,11 +551,11 @@ static int mc_probe(struct platform_device *pdev)
" cfg-amp:%d", amp_num);
if (!card->components)
return -ENOMEM;
- if (mach->mach_params.dmic_num) {
+ if (soc_sdw_quirk & ASOC_SDW_ACP_DMIC) {
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
"%s mic:dmic cfg-mics:%d",
card->components,
- mach->mach_params.dmic_num);
+ 1);
if (!card->components)
return -ENOMEM;
}
diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c
index 6215e31ecedd..36ecef7013b9 100644
--- a/sound/soc/amd/acp/acp-sof-mach.c
+++ b/sound/soc/amd/acp/acp-sof-mach.c
@@ -110,7 +110,7 @@ static int acp_sof_probe(struct platform_device *pdev)
acp_card_drvdata = card->drvdata;
dmi_id = dmi_first_match(acp_quirk_table);
- if (dmi_id && dmi_id->driver_data)
+ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE)
acp_card_drvdata->tdm_mode = dmi_id->driver_data;
acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev;
diff --git a/sound/soc/amd/ps/ps-pdm-dma.c b/sound/soc/amd/ps/ps-pdm-dma.c
index 7c529fc6ba99..04c014349347 100644
--- a/sound/soc/amd/ps/ps-pdm-dma.c
+++ b/sound/soc/amd/ps/ps-pdm-dma.c
@@ -351,7 +351,8 @@ static const struct snd_soc_component_driver acp63_pdm_component = {
.close = acp63_pdm_dma_close,
.hw_params = acp63_pdm_dma_hw_params,
.pointer = acp63_pdm_dma_pointer,
- .pcm_construct = acp63_pdm_dma_new,
+ .pcm_new = acp63_pdm_dma_new,
+ .use_dai_pcm_id = true,
};
static int acp63_pdm_audio_probe(struct platform_device *pdev)
diff --git a/sound/soc/amd/ps/ps-sdw-dma.c b/sound/soc/amd/ps/ps-sdw-dma.c
index 366d7c4bb07e..f27ebbd21379 100644
--- a/sound/soc/amd/ps/ps-sdw-dma.c
+++ b/sound/soc/amd/ps/ps-sdw-dma.c
@@ -634,7 +634,7 @@ static const struct snd_soc_component_driver acp63_sdw_component = {
.hw_params = acp63_sdw_dma_hw_params,
.trigger = acp63_sdw_dma_trigger,
.pointer = acp63_sdw_dma_pointer,
- .pcm_construct = acp63_sdw_dma_new,
+ .pcm_new = acp63_sdw_dma_new,
.use_dai_pcm_id = true,
};
diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c
index 4529404ebd93..37ea5c572eb9 100644
--- a/sound/soc/amd/raven/acp3x-pcm-dma.c
+++ b/sound/soc/amd/raven/acp3x-pcm-dma.c
@@ -363,7 +363,7 @@ static const struct snd_soc_component_driver acp3x_i2s_component = {
.close = acp3x_dma_close,
.hw_params = acp3x_dma_hw_params,
.pointer = acp3x_dma_pointer,
- .pcm_construct = acp3x_dma_new,
+ .pcm_new = acp3x_dma_new,
};
static int acp3x_audio_probe(struct platform_device *pdev)
diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c b/sound/soc/amd/renoir/acp3x-pdm-dma.c
index e832c7c4b96f..e60e3821703c 100644
--- a/sound/soc/amd/renoir/acp3x-pdm-dma.c
+++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c
@@ -376,7 +376,7 @@ static const struct snd_soc_component_driver acp_pdm_component = {
.close = acp_pdm_dma_close,
.hw_params = acp_pdm_dma_hw_params,
.pointer = acp_pdm_dma_pointer,
- .pcm_construct = acp_pdm_dma_new,
+ .pcm_new = acp_pdm_dma_new,
.legacy_dai_naming = 1,
};
diff --git a/sound/soc/amd/vangogh/acp5x-pcm-dma.c b/sound/soc/amd/vangogh/acp5x-pcm-dma.c
index 6ce82cd8859b..831e30e9b042 100644
--- a/sound/soc/amd/vangogh/acp5x-pcm-dma.c
+++ b/sound/soc/amd/vangogh/acp5x-pcm-dma.c
@@ -357,7 +357,7 @@ static const struct snd_soc_component_driver acp5x_i2s_component = {
.close = acp5x_dma_close,
.hw_params = acp5x_dma_hw_params,
.pointer = acp5x_dma_pointer,
- .pcm_construct = acp5x_dma_new,
+ .pcm_new = acp5x_dma_new,
};
static int acp5x_audio_probe(struct platform_device *pdev)
diff --git a/sound/soc/amd/yc/acp6x-pdm-dma.c b/sound/soc/amd/yc/acp6x-pdm-dma.c
index 1c8aad849916..710db721ffa4 100644
--- a/sound/soc/amd/yc/acp6x-pdm-dma.c
+++ b/sound/soc/amd/yc/acp6x-pdm-dma.c
@@ -346,7 +346,7 @@ static const struct snd_soc_component_driver acp6x_pdm_component = {
.close = acp6x_pdm_dma_close,
.hw_params = acp6x_pdm_dma_hw_params,
.pointer = acp6x_pdm_dma_pointer,
- .pcm_construct = acp6x_pdm_dma_new,
+ .pcm_new = acp6x_pdm_dma_new,
.legacy_dai_naming = 1,
};
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index fdda1b747bf7..8ab2e60f80b4 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -2496,13 +2496,13 @@ static int ab8500_codec_probe(struct snd_soc_component *component)
return status;
}
fc = (struct filter_control *)
- &ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value;
+ ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value;
drvdata->anc_fir_values = (long *)fc->value;
fc = (struct filter_control *)
- &ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value;
+ ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value;
drvdata->anc_iir_values = (long *)fc->value;
fc = (struct filter_control *)
- &ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value;
+ ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value;
drvdata->sid_fir_values = (long *)fc->value;
snd_soc_dapm_disable_pin(dapm, "ANC Configure Input");
diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index af87ebae98cb..0ddf9a8d39a0 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -108,8 +108,6 @@ int cs35l56_set_patch(struct cs35l56_base *cs35l56_base)
EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, "SND_SOC_CS35L56_SHARED");
static const struct reg_default cs35l56_reg_defaults[] = {
- /* no defaults for OTP_MEM - first read populates cache */
-
{ CS35L56_ASP1_ENABLES1, 0x00000000 },
{ CS35L56_ASP1_CONTROL1, 0x00000028 },
{ CS35L56_ASP1_CONTROL2, 0x18180200 },
@@ -138,8 +136,6 @@ static const struct reg_default cs35l56_reg_defaults[] = {
};
static const struct reg_default cs35l63_reg_defaults[] = {
- /* no defaults for OTP_MEM - first read populates cache */
-
{ CS35L56_ASP1_ENABLES1, 0x00000000 },
{ CS35L56_ASP1_CONTROL1, 0x00000028 },
{ CS35L56_ASP1_CONTROL2, 0x18180200 },
@@ -282,6 +278,9 @@ static bool cs35l56_common_volatile_reg(unsigned int reg)
case CS35L56_GLOBAL_ENABLES: /* owned by firmware */
case CS35L56_BLOCK_ENABLES: /* owned by firmware */
case CS35L56_BLOCK_ENABLES2: /* owned by firmware */
+ case CS35L56_OTP_MEM_53:
+ case CS35L56_OTP_MEM_54:
+ case CS35L56_OTP_MEM_55:
case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG:
case CS35L56_UPDATE_REGS:
case CS35L56_REFCLK_INPUT: /* owned by firmware */
diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index 36e25e48b354..9f351565dc82 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -809,6 +809,7 @@ static bool tas2764_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case TAS2764_SW_RST:
+ case TAS2764_TEMP:
case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4:
case TAS2764_INT_CLK_CFG:
return true;
diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c
index 6f878b01716f..2ce3011119bd 100644
--- a/sound/soc/codecs/tas2770.c
+++ b/sound/soc/codecs/tas2770.c
@@ -549,7 +549,7 @@ static int tas2770_read_die_temp(struct tas2770_priv *tas2770, long *result)
/*
* As per datasheet: divide register by 16 and subtract 93 to get
* degrees Celsius. hwmon requires millidegrees. Let's avoid rounding
- * errors by subtracting 93 * 16 then multiplying by 1000 / 16.
+ * errors by subtracting 93 * 16 and scaling before dividing.
*
* NOTE: The ADC registers are initialised to 0 on reset. This means
* that the temperature will read -93 *C until the chip is brought out
@@ -558,7 +558,7 @@ static int tas2770_read_die_temp(struct tas2770_priv *tas2770, long *result)
* value read back from its registers will be the last value sampled
* before entering software shutdown.
*/
- *result = (reading - (93 * 16)) * (1000 / 16);
+ *result = (reading - (93 * 16)) * 1000 / 16;
return 0;
}
diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
index 599e439b359a..114a6c0b6b73 100644
--- a/sound/soc/fsl/fsl_easrc.c
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -54,6 +54,9 @@ static int fsl_easrc_iec958_put_bits(struct snd_kcontrol *kcontrol,
unsigned int regval = ucontrol->value.integer.value[0];
int ret;
+ if (regval < EASRC_WIDTH_16_BIT || regval > EASRC_WIDTH_24_BIT)
+ return -EINVAL;
+
ret = (easrc_priv->bps_iec958[mc->regbase] != regval);
easrc_priv->bps_iec958[mc->regbase] = regval;
@@ -70,8 +73,16 @@ static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol,
struct soc_mreg_control *mc =
(struct soc_mreg_control *)kcontrol->private_value;
- ucontrol->value.enumerated.item[0] = easrc_priv->bps_iec958[mc->regbase];
+ ucontrol->value.integer.value[0] = easrc_priv->bps_iec958[mc->regbase];
+
+ return 0;
+}
+static int fsl_easrc_iec958_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
return 0;
}
@@ -81,11 +92,33 @@ static int fsl_easrc_get_reg(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_mreg_control *mc =
(struct soc_mreg_control *)kcontrol->private_value;
- unsigned int regval;
+ struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component);
+ unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status;
+ int ret;
+
+ ret = regmap_read(easrc->regmap, REG_EASRC_CS0(mc->regbase), ®val[0]);
+ if (ret)
+ return ret;
- regval = snd_soc_component_read(component, mc->regbase);
+ ret = regmap_read(easrc->regmap, REG_EASRC_CS1(mc->regbase), ®val[1]);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(easrc->regmap, REG_EASRC_CS2(mc->regbase), ®val[2]);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(easrc->regmap, REG_EASRC_CS3(mc->regbase), ®val[3]);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(easrc->regmap, REG_EASRC_CS4(mc->regbase), ®val[4]);
+ if (ret)
+ return ret;
- ucontrol->value.integer.value[0] = regval;
+ ret = regmap_read(easrc->regmap, REG_EASRC_CS5(mc->regbase), ®val[5]);
+ if (ret)
+ return ret;
return 0;
}
@@ -97,22 +130,62 @@ static int fsl_easrc_set_reg(struct snd_kcontrol *kcontrol,
struct soc_mreg_control *mc =
(struct soc_mreg_control *)kcontrol->private_value;
struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component);
- unsigned int regval = ucontrol->value.integer.value[0];
- bool changed;
+ unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status;
+ bool changed, changed_all = false;
int ret;
- ret = regmap_update_bits_check(easrc->regmap, mc->regbase,
- GENMASK(31, 0), regval, &changed);
- if (ret != 0)
+ ret = pm_runtime_resume_and_get(component->dev);
+ if (ret)
return ret;
- return changed;
+ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS0(mc->regbase),
+ GENMASK(31, 0), regval[0], &changed);
+ if (ret != 0)
+ goto err;
+ changed_all |= changed;
+
+ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS1(mc->regbase),
+ GENMASK(31, 0), regval[1], &changed);
+ if (ret != 0)
+ goto err;
+ changed_all |= changed;
+
+ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS2(mc->regbase),
+ GENMASK(31, 0), regval[2], &changed);
+ if (ret != 0)
+ goto err;
+ changed_all |= changed;
+
+ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS3(mc->regbase),
+ GENMASK(31, 0), regval[3], &changed);
+ if (ret != 0)
+ goto err;
+ changed_all |= changed;
+
+ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS4(mc->regbase),
+ GENMASK(31, 0), regval[4], &changed);
+ if (ret != 0)
+ goto err;
+ changed_all |= changed;
+
+ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS5(mc->regbase),
+ GENMASK(31, 0), regval[5], &changed);
+ if (ret != 0)
+ goto err;
+ changed_all |= changed;
+err:
+ pm_runtime_put_autosuspend(component->dev);
+
+ if (ret != 0)
+ return ret;
+ else
+ return changed_all;
}
#define SOC_SINGLE_REG_RW(xname, xreg) \
{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = (xname), \
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
- .info = snd_soc_info_xr_sx, .get = fsl_easrc_get_reg, \
+ .info = fsl_easrc_iec958_info, .get = fsl_easrc_get_reg, \
.put = fsl_easrc_set_reg, \
.private_value = (unsigned long)&(struct soc_mreg_control) \
{ .regbase = xreg, .regcount = 1, .nbits = 32, \
@@ -143,30 +216,10 @@ static const struct snd_kcontrol_new fsl_easrc_snd_controls[] = {
SOC_SINGLE_VAL_RW("Context 2 IEC958 Bits Per Sample", 2),
SOC_SINGLE_VAL_RW("Context 3 IEC958 Bits Per Sample", 3),
- SOC_SINGLE_REG_RW("Context 0 IEC958 CS0", REG_EASRC_CS0(0)),
- SOC_SINGLE_REG_RW("Context 1 IEC958 CS0", REG_EASRC_CS0(1)),
- SOC_SINGLE_REG_RW("Context 2 IEC958 CS0", REG_EASRC_CS0(2)),
- SOC_SINGLE_REG_RW("Context 3 IEC958 CS0", REG_EASRC_CS0(3)),
- SOC_SINGLE_REG_RW("Context 0 IEC958 CS1", REG_EASRC_CS1(0)),
- SOC_SINGLE_REG_RW("Context 1 IEC958 CS1", REG_EASRC_CS1(1)),
- SOC_SINGLE_REG_RW("Context 2 IEC958 CS1", REG_EASRC_CS1(2)),
- SOC_SINGLE_REG_RW("Context 3 IEC958 CS1", REG_EASRC_CS1(3)),
- SOC_SINGLE_REG_RW("Context 0 IEC958 CS2", REG_EASRC_CS2(0)),
- SOC_SINGLE_REG_RW("Context 1 IEC958 CS2", REG_EASRC_CS2(1)),
- SOC_SINGLE_REG_RW("Context 2 IEC958 CS2", REG_EASRC_CS2(2)),
- SOC_SINGLE_REG_RW("Context 3 IEC958 CS2", REG_EASRC_CS2(3)),
- SOC_SINGLE_REG_RW("Context 0 IEC958 CS3", REG_EASRC_CS3(0)),
- SOC_SINGLE_REG_RW("Context 1 IEC958 CS3", REG_EASRC_CS3(1)),
- SOC_SINGLE_REG_RW("Context 2 IEC958 CS3", REG_EASRC_CS3(2)),
- SOC_SINGLE_REG_RW("Context 3 IEC958 CS3", REG_EASRC_CS3(3)),
- SOC_SINGLE_REG_RW("Context 0 IEC958 CS4", REG_EASRC_CS4(0)),
- SOC_SINGLE_REG_RW("Context 1 IEC958 CS4", REG_EASRC_CS4(1)),
- SOC_SINGLE_REG_RW("Context 2 IEC958 CS4", REG_EASRC_CS4(2)),
- SOC_SINGLE_REG_RW("Context 3 IEC958 CS4", REG_EASRC_CS4(3)),
- SOC_SINGLE_REG_RW("Context 0 IEC958 CS5", REG_EASRC_CS5(0)),
- SOC_SINGLE_REG_RW("Context 1 IEC958 CS5", REG_EASRC_CS5(1)),
- SOC_SINGLE_REG_RW("Context 2 IEC958 CS5", REG_EASRC_CS5(2)),
- SOC_SINGLE_REG_RW("Context 3 IEC958 CS5", REG_EASRC_CS5(3)),
+ SOC_SINGLE_REG_RW("Context 0 IEC958 CS", 0),
+ SOC_SINGLE_REG_RW("Context 1 IEC958 CS", 1),
+ SOC_SINGLE_REG_RW("Context 2 IEC958 CS", 2),
+ SOC_SINGLE_REG_RW("Context 3 IEC958 CS", 3),
};
/*
diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c
index d6cde2757c6d..2e887f1f1f36 100644
--- a/sound/soc/fsl/fsl_micfil.c
+++ b/sound/soc/fsl/fsl_micfil.c
@@ -210,15 +210,23 @@ static int micfil_range_set(struct snd_kcontrol *kcontrol,
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int shift = mc->shift;
int max_range, new_range;
+ int ret;
new_range = ucontrol->value.integer.value[0];
max_range = micfil_get_max_range(micfil);
if (new_range > max_range)
dev_warn(&micfil->pdev->dev, "range makes channel %d data unreliable\n", shift / 4);
- regmap_update_bits(micfil->regmap, REG_MICFIL_OUT_CTRL, 0xF << shift, new_range << shift);
+ ret = pm_runtime_resume_and_get(cmpnt->dev);
+ if (ret)
+ return ret;
- return 0;
+ ret = snd_soc_component_update_bits(cmpnt, REG_MICFIL_OUT_CTRL, 0xF << shift,
+ new_range << shift);
+
+ pm_runtime_put_autosuspend(cmpnt->dev);
+
+ return ret;
}
static int micfil_set_quality(struct fsl_micfil *micfil)
@@ -281,10 +289,34 @@ static int micfil_quality_set(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt);
+ int val = ucontrol->value.integer.value[0];
+ bool change = false;
+ int old_val;
+ int ret;
+
+ if (val < QUALITY_HIGH || val > QUALITY_VLOW2)
+ return -EINVAL;
+
+ if (micfil->quality != val) {
+ ret = pm_runtime_resume_and_get(cmpnt->dev);
+ if (ret)
+ return ret;
+
+ old_val = micfil->quality;
+ micfil->quality = val;
+ ret = micfil_set_quality(micfil);
- micfil->quality = ucontrol->value.integer.value[0];
+ pm_runtime_put_autosuspend(cmpnt->dev);
+
+ if (ret) {
+ micfil->quality = old_val;
+ return ret;
+ }
- return micfil_set_quality(micfil);
+ change = true;
+ }
+
+ return change;
}
static const char * const micfil_hwvad_enable[] = {
@@ -343,6 +375,10 @@ static int micfil_put_dc_remover_state(struct snd_kcontrol *kcontrol,
if (val < 0 || val > 3)
return -EINVAL;
+ ret = pm_runtime_resume_and_get(comp->dev);
+ if (ret)
+ return ret;
+
micfil->dc_remover = val;
/* Calculate total value for all channels */
@@ -352,10 +388,10 @@ static int micfil_put_dc_remover_state(struct snd_kcontrol *kcontrol,
/* Update DC Remover mode for all channels */
ret = snd_soc_component_update_bits(comp, REG_MICFIL_DC_CTRL,
MICFIL_DC_CTRL_CONFIG, reg_val);
- if (ret < 0)
- return ret;
- return 0;
+ pm_runtime_put_autosuspend(comp->dev);
+
+ return ret;
}
static int micfil_get_dc_remover_state(struct snd_kcontrol *kcontrol,
@@ -377,10 +413,15 @@ static int hwvad_put_enable(struct snd_kcontrol *kcontrol,
unsigned int *item = ucontrol->value.enumerated.item;
struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
int val = snd_soc_enum_item_to_val(e, item[0]);
+ bool change = false;
+
+ if (val < 0 || val > 1)
+ return -EINVAL;
+ change = (micfil->vad_enabled != val);
micfil->vad_enabled = val;
- return 0;
+ return change;
}
static int hwvad_get_enable(struct snd_kcontrol *kcontrol,
@@ -402,13 +443,18 @@ static int hwvad_put_init_mode(struct snd_kcontrol *kcontrol,
unsigned int *item = ucontrol->value.enumerated.item;
struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
int val = snd_soc_enum_item_to_val(e, item[0]);
+ bool change = false;
+
+ if (val < MICFIL_HWVAD_ENVELOPE_MODE || val > MICFIL_HWVAD_ENERGY_MODE)
+ return -EINVAL;
/* 0 - Envelope-based Mode
* 1 - Energy-based Mode
*/
+ change = (micfil->vad_init_mode != val);
micfil->vad_init_mode = val;
- return 0;
+ return change;
}
static int hwvad_get_init_mode(struct snd_kcontrol *kcontrol,
@@ -503,7 +549,13 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
SOC_SINGLE("HWVAD ZCD Adjustment", REG_MICFIL_VAD0_ZCD, 8, 15, 0),
SOC_SINGLE("HWVAD ZCD And Behavior Switch",
REG_MICFIL_VAD0_ZCD, 4, 1, 0),
- SOC_SINGLE_BOOL_EXT("VAD Detected", 0, hwvad_detected, NULL),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .name = "VAD Detected",
+ .info = snd_soc_info_bool_ext,
+ .get = hwvad_detected,
+ },
};
static int fsl_micfil_use_verid(struct device *dev)
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c
index a268fb81a2f8..d7a823384c08 100644
--- a/sound/soc/fsl/fsl_xcvr.c
+++ b/sound/soc/fsl/fsl_xcvr.c
@@ -115,10 +115,17 @@ static int fsl_xcvr_arc_mode_put(struct snd_kcontrol *kcontrol,
struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int *item = ucontrol->value.enumerated.item;
+ int val = snd_soc_enum_item_to_val(e, item[0]);
+ int ret;
- xcvr->arc_mode = snd_soc_enum_item_to_val(e, item[0]);
+ if (val < 0 || val > 1)
+ return -EINVAL;
- return 0;
+ ret = (xcvr->arc_mode != val);
+
+ xcvr->arc_mode = val;
+
+ return ret;
}
static int fsl_xcvr_arc_mode_get(struct snd_kcontrol *kcontrol,
@@ -218,10 +225,17 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol,
struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int *item = ucontrol->value.enumerated.item;
+ int val = snd_soc_enum_item_to_val(e, item[0]);
struct snd_soc_card *card = dai->component->card;
struct snd_soc_pcm_runtime *rtd;
+ int ret;
+
+ if (val < FSL_XCVR_MODE_SPDIF || val > FSL_XCVR_MODE_EARC)
+ return -EINVAL;
- xcvr->mode = snd_soc_enum_item_to_val(e, item[0]);
+ ret = (xcvr->mode != val);
+
+ xcvr->mode = val;
fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
(xcvr->mode == FSL_XCVR_MODE_ARC));
@@ -231,7 +245,7 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol,
rtd = snd_soc_get_pcm_runtime(card, card->dai_link);
rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count =
(xcvr->mode == FSL_XCVR_MODE_SPDIF ? 1 : 0);
- return 0;
+ return ret;
}
static int fsl_xcvr_mode_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 8a5f41704739..74e8f2ab7ffc 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -77,6 +77,7 @@ static bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
struct snd_soc_dai *dai = snd_soc_find_dai_with_mutex(dlc);
if (dai && (dai->component->driver->pcm_construct ||
+ dai->component->driver->pcm_new ||
(dai->driver->ops && dai->driver->ops->pcm_new)))
return true;
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 412555e626b8..63367364916a 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -95,7 +95,7 @@ config SND_SOC_INTEL_KEEMBAY
config SND_SOC_INTEL_AVS
tristate "Intel AVS driver"
- depends on X86 || COMPILE_TEST
+ depends on X86
depends on PCI
depends on COMMON_CLK
select ACPI_NHLT if ACPI
diff --git a/sound/soc/intel/avs/tgl.c b/sound/soc/intel/avs/tgl.c
index afb066516101..a7123639de43 100644
--- a/sound/soc/intel/avs/tgl.c
+++ b/sound/soc/intel/avs/tgl.c
@@ -7,12 +7,11 @@
//
#include <linux/pci.h>
+#include <asm/cpuid/api.h>
#include "avs.h"
#include "debug.h"
#include "messages.h"
-#define CPUID_TSC_LEAF 0x15
-
static int avs_tgl_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power)
{
core_mask &= AVS_MAIN_CORE_MASK;
@@ -40,22 +39,37 @@ static int avs_tgl_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stal
return avs_dsp_core_stall(adev, core_mask, stall);
}
-static int avs_tgl_config_basefw(struct avs_dev *adev)
+/*
+ * Succeed if CPUID(0x15) is not available, or if the nominal core crystal clock
+ * frequency cannot be enumerated from it. There is nothing to do in both cases.
+ */
+static int avs_tgl_set_xtal_freq(struct avs_dev *adev)
{
- struct pci_dev *pci = adev->base.pci;
- struct avs_bus_hwid hwid;
+ unsigned int freq;
int ret;
-#ifdef CONFIG_X86
- unsigned int ecx;
-#include <asm/cpuid/api.h>
- ecx = cpuid_ecx(CPUID_TSC_LEAF);
- if (ecx) {
- ret = avs_ipc_set_fw_config(adev, 1, AVS_FW_CFG_XTAL_FREQ_HZ, sizeof(ecx), &ecx);
+ if (boot_cpu_data.cpuid_level < CPUID_LEAF_TSC)
+ return 0;
+
+ freq = cpuid_ecx(CPUID_LEAF_TSC);
+ if (freq) {
+ ret = avs_ipc_set_fw_config(adev, 1, AVS_FW_CFG_XTAL_FREQ_HZ, sizeof(freq), &freq);
if (ret)
return AVS_IPC_RET(ret);
}
-#endif
+
+ return 0;
+}
+
+static int avs_tgl_config_basefw(struct avs_dev *adev)
+{
+ struct pci_dev *pci = adev->base.pci;
+ struct avs_bus_hwid hwid;
+ int ret;
+
+ ret = avs_tgl_set_xtal_freq(adev);
+ if (ret)
+ return ret;
hwid.device = pci->device;
hwid.subsystem = pci->subsystem_vendor | (pci->subsystem_device << 16);
diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c
index 241c3b4479c6..ff8cd55b0d89 100644
--- a/sound/soc/qcom/qdsp6/audioreach.c
+++ b/sound/soc/qcom/qdsp6/audioreach.c
@@ -1365,9 +1365,14 @@ int audioreach_set_media_format(struct q6apm_graph *graph,
case MODULE_ID_SPEAKER_PROTECTION:
rc = audioreach_speaker_protection(graph, module,
PARAM_ID_SP_OP_MODE_NORMAL);
+ if (!rc)
+ rc = audioreach_module_enable(graph, module, true);
+
break;
case MODULE_ID_SPEAKER_PROTECTION_VI:
rc = audioreach_speaker_protection_vi(graph, module, cfg);
+ if (!rc)
+ rc = audioreach_module_enable(graph, module, true);
break;
default:
diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c
index e732fac9b8ca..1f69fba6de26 100644
--- a/sound/soc/qcom/qdsp6/topology.c
+++ b/sound/soc/qcom/qdsp6/topology.c
@@ -952,9 +952,6 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp,
struct audioreach_container *cont;
struct audioreach_module *mod;
- mod = dobj->private;
- cont = mod->container;
-
if (w->id == snd_soc_dapm_mixer) {
/* virtual widget */
struct snd_ar_control *scontrol = dobj->private;
@@ -963,6 +960,11 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp,
kfree(scontrol);
return 0;
}
+ mod = dobj->private;
+ if (!mod)
+ return 0;
+
+ cont = mod->container;
mutex_lock(&apm->lock);
idr_remove(&apm->modules_idr, mod->instance_id);
diff --git a/sound/soc/renesas/rcar/core.c b/sound/soc/renesas/rcar/core.c
index 69fb19964a71..2dc078358612 100644
--- a/sound/soc/renesas/rcar/core.c
+++ b/sound/soc/renesas/rcar/core.c
@@ -1974,7 +1974,7 @@ static int rsnd_probe(struct platform_device *pdev)
* asoc register
*/
ci = 0;
- for (i = 0; priv->component_dais[i] > 0; i++) {
+ for (i = 0; i < RSND_MAX_COMPONENT && priv->component_dais[i] > 0; i++) {
int nr = priv->component_dais[i];
ret = devm_snd_soc_register_component(dev, &rsnd_soc_component,
diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c
index 1bf614dbdf4d..ed393e5034a4 100644
--- a/sound/soc/rockchip/rockchip_sai.c
+++ b/sound/soc/rockchip/rockchip_sai.c
@@ -628,6 +628,10 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK | SAI_XCR_CSR_MASK, val);
+ if (!sai->is_tdm)
+ regmap_update_bits(sai->regmap, reg, SAI_XCR_SBW_MASK,
+ SAI_XCR_SBW(params_physical_width(params)));
+
regmap_read(sai->regmap, reg, &val);
slot_width = SAI_XCR_SBW_V(val);
diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c
index a0191e5a5a7d..b6536eeecf58 100644
--- a/sound/soc/sdca/sdca_asoc.c
+++ b/sound/soc/sdca/sdca_asoc.c
@@ -51,6 +51,25 @@ static bool readonly_control(struct sdca_control *control)
return control->has_fixed || control->mode == SDCA_ACCESS_MODE_RO;
}
+static int ge_count_routes(struct sdca_entity *entity)
+{
+ int count = 0;
+ int i, j;
+
+ for (i = 0; i < entity->ge.num_modes; i++) {
+ struct sdca_ge_mode *mode = &entity->ge.modes[i];
+
+ for (j = 0; j < mode->num_controls; j++) {
+ struct sdca_ge_control *affected = &mode->controls[j];
+
+ if (affected->sel != SDCA_CTL_SU_SELECTOR || affected->val)
+ count++;
+ }
+ }
+
+ return count;
+}
+
/**
* sdca_asoc_count_component - count the various component parts
* @dev: Pointer to the device against which allocations will be done.
@@ -74,6 +93,7 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun
int *num_widgets, int *num_routes, int *num_controls,
int *num_dais)
{
+ struct sdca_control *control;
int i, j;
*num_widgets = function->num_entities - 1;
@@ -83,6 +103,7 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun
for (i = 0; i < function->num_entities - 1; i++) {
struct sdca_entity *entity = &function->entities[i];
+ bool skip_primary_routes = false;
/* Add supply/DAI widget connections */
switch (entity->type) {
@@ -96,6 +117,17 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun
case SDCA_ENTITY_TYPE_PDE:
*num_routes += entity->pde.num_managed;
break;
+ case SDCA_ENTITY_TYPE_GE:
+ *num_routes += ge_count_routes(entity);
+ skip_primary_routes = true;
+ break;
+ case SDCA_ENTITY_TYPE_SU:
+ control = sdca_selector_find_control(dev, entity, SDCA_CTL_SU_SELECTOR);
+ if (!control)
+ return -EINVAL;
+
+ skip_primary_routes = (control->layers == SDCA_ACCESS_LAYER_DEVICE);
+ break;
default:
break;
}
@@ -104,7 +136,8 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun
(*num_routes)++;
/* Add primary entity connections from DisCo */
- *num_routes += entity->num_sources;
+ if (!skip_primary_routes)
+ *num_routes += entity->num_sources;
for (j = 0; j < entity->num_controls; j++) {
if (exported_control(entity, &entity->controls[j]))
@@ -442,7 +475,6 @@ static int entity_parse_su_device(struct device *dev,
struct snd_soc_dapm_route **route)
{
struct sdca_control_range *range;
- int num_routes = 0;
int i, j;
if (!entity->group) {
@@ -478,11 +510,6 @@ static int entity_parse_su_device(struct device *dev,
return -EINVAL;
}
- if (++num_routes > entity->num_sources) {
- dev_err(dev, "%s: too many input routes\n", entity->label);
- return -EINVAL;
- }
-
term = sdca_range_search(range, SDCA_SELECTED_MODE_INDEX,
mode->val, SDCA_SELECTED_MODE_TERM_TYPE);
if (!term) {
diff --git a/sound/soc/sdca/sdca_class.c b/sound/soc/sdca/sdca_class.c
index 918b638acb57..5def6ae2d99f 100644
--- a/sound/soc/sdca/sdca_class.c
+++ b/sound/soc/sdca/sdca_class.c
@@ -137,6 +137,13 @@ static const struct regmap_config class_dev_regmap_config = {
.unlock = class_regmap_unlock,
};
+static void class_remove_functions(void *data)
+{
+ struct sdca_class_drv *drv = data;
+
+ sdca_dev_unregister_functions(drv->sdw);
+}
+
static void class_boot_work(struct work_struct *work)
{
struct sdca_class_drv *drv = container_of(work,
@@ -157,6 +164,11 @@ static void class_boot_work(struct work_struct *work)
if (ret)
goto err;
+ /* Ensure function drivers are removed before the IRQ is destroyed */
+ ret = devm_add_action_or_reset(drv->dev, class_remove_functions, drv);
+ if (ret)
+ goto err;
+
dev_dbg(drv->dev, "boot work complete\n");
pm_runtime_mark_last_busy(drv->dev);
@@ -168,15 +180,6 @@ static void class_boot_work(struct work_struct *work)
pm_runtime_put_sync(drv->dev);
}
-static void class_dev_remove(void *data)
-{
- struct sdca_class_drv *drv = data;
-
- cancel_work_sync(&drv->boot_work);
-
- sdca_dev_unregister_functions(drv->sdw);
-}
-
static int class_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id)
{
struct device *dev = &sdw->dev;
@@ -230,15 +233,19 @@ static int class_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id
if (ret)
return ret;
- ret = devm_add_action_or_reset(dev, class_dev_remove, drv);
- if (ret)
- return ret;
-
queue_work(system_long_wq, &drv->boot_work);
return 0;
}
+static void class_sdw_remove(struct sdw_slave *sdw)
+{
+ struct device *dev = &sdw->dev;
+ struct sdca_class_drv *drv = dev_get_drvdata(dev);
+
+ cancel_work_sync(&drv->boot_work);
+}
+
static int class_suspend(struct device *dev)
{
struct sdca_class_drv *drv = dev_get_drvdata(dev);
@@ -328,6 +335,7 @@ static struct sdw_driver class_sdw_driver = {
},
.probe = class_sdw_probe,
+ .remove = class_sdw_remove,
.id_table = class_sdw_id,
.ops = &class_sdw_ops,
};
diff --git a/sound/soc/sdca/sdca_fdl.c b/sound/soc/sdca/sdca_fdl.c
index 07892bc3a44e..994821a6df61 100644
--- a/sound/soc/sdca/sdca_fdl.c
+++ b/sound/soc/sdca/sdca_fdl.c
@@ -46,11 +46,6 @@ int sdca_reset_function(struct device *dev, struct sdca_function_data *function,
if (ret) // Allowed for function reset to not be implemented
return 0;
- if (!function->reset_max_delay) {
- dev_err(dev, "No reset delay specified in DisCo\n");
- return -EINVAL;
- }
-
/*
* Poll up to 16 times but no more than once per ms, these are just
* arbitrarily selected values, so may be fine tuned in future.
diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c
index dca60ee8e62c..fd6a254c9530 100644
--- a/sound/soc/sdca/sdca_functions.c
+++ b/sound/soc/sdca/sdca_functions.c
@@ -2176,8 +2176,12 @@ int sdca_parse_function(struct device *dev, struct sdw_slave *sdw,
ret = fwnode_property_read_u32(function_desc->node,
"mipi-sdca-function-reset-max-delay", &tmp);
- if (!ret)
+ if (ret || tmp == 0) {
+ dev_dbg(dev, "reset delay missing, defaulting to 100mS\n");
+ function->reset_max_delay = 100000;
+ } else {
function->reset_max_delay = tmp;
+ }
dev_dbg(dev, "%pfwP: name %s busy delay %dus reset delay %dus\n",
function->desc->node, function->desc->name,
diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c
index 89f236ab3034..77ad33383974 100644
--- a/sound/soc/soc-component.c
+++ b/sound/soc/soc-component.c
@@ -1042,6 +1042,11 @@ int snd_soc_pcm_component_new(struct snd_soc_pcm_runtime *rtd)
if (ret < 0)
return soc_component_ret(component, ret);
}
+ if (component->driver->pcm_new) {
+ ret = component->driver->pcm_new(component, rtd);
+ if (ret < 0)
+ return soc_component_ret(component, ret);
+ }
}
return 0;
@@ -1055,9 +1060,12 @@ void snd_soc_pcm_component_free(struct snd_soc_pcm_runtime *rtd)
if (!rtd->pcm)
return;
- for_each_rtd_components(rtd, i, component)
+ for_each_rtd_components(rtd, i, component) {
if (component->driver->pcm_destruct)
component->driver->pcm_destruct(component, rtd->pcm);
+ if (component->driver->pcm_free)
+ component->driver->pcm_free(component, rtd->pcm);
+ }
}
int snd_soc_pcm_component_prepare(struct snd_pcm_substream *substream)
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 7b81dffc6a93..b8402802ae78 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -69,10 +69,10 @@ static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback)
snd_soc_dai_digital_mute(codec_dai, 1, stream);
if (!snd_soc_dai_active(cpu_dai))
- cpu_dai->symmetric_rate = 0;
+ soc_pcm_set_dai_params(cpu_dai, NULL);
if (!snd_soc_dai_active(codec_dai))
- codec_dai->symmetric_rate = 0;
+ soc_pcm_set_dai_params(codec_dai, NULL);
snd_soc_link_compr_shutdown(cstream, rollback);
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index afa9fad4457f..9b12eedb77c3 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -423,8 +423,8 @@ void dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, int event)
snd_soc_dapm_stream_event(fe, dir, event);
}
-static void soc_pcm_set_dai_params(struct snd_soc_dai *dai,
- struct snd_pcm_hw_params *params)
+void soc_pcm_set_dai_params(struct snd_soc_dai *dai,
+ struct snd_pcm_hw_params *params)
{
if (params) {
dai->symmetric_rate = params_rate(params);
diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c
index 90f056eae1c3..a676ffc2379d 100644
--- a/sound/soc/sof/compress.c
+++ b/sound/soc/sof/compress.c
@@ -255,6 +255,7 @@ static int sof_compr_set_params(struct snd_soc_component *component,
sstream->sampling_rate = params->codec.sample_rate;
sstream->channels = params->codec.ch_out;
sstream->sample_container_bytes = pcm->params.sample_container_bytes;
+ sstream->codec_params = params->codec;
spcm->prepared[cstream->direction] = true;
@@ -267,9 +268,10 @@ static int sof_compr_set_params(struct snd_soc_component *component,
static int sof_compr_get_params(struct snd_soc_component *component,
struct snd_compr_stream *cstream, struct snd_codec *params)
{
- /* TODO: we don't query the supported codecs for now, if the
- * application asks for an unsupported codec the set_params() will fail.
- */
+ struct sof_compr_stream *sstream = cstream->runtime->private_data;
+
+ *params = sstream->codec_params;
+
return 0;
}
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
index 1c04b5d9c0d8..5c1f3b427cdb 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -480,16 +480,20 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st
struct snd_dma_buffer *dmab,
struct snd_pcm_hw_params *params)
{
- struct hdac_stream *hstream = &hext_stream->hstream;
- int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
+ struct hdac_stream *hstream;
+ int sd_offset;
int ret;
- u32 mask = 0x1 << hstream->index;
+ u32 mask;
if (!hext_stream) {
dev_err(sdev->dev, "error: no stream available\n");
return -ENODEV;
}
+ hstream = &hext_stream->hstream;
+ sd_offset = SOF_STREAM_SD_OFFSET(hstream);
+ mask = 0x1 << hstream->index;
+
if (!dmab) {
dev_err(sdev->dev, "error: no dma buffer allocated!\n");
return -ENODEV;
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index 8a240dcb7fcb..5fa773bb2678 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -1399,7 +1399,8 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
link_mask |= BIT(peripherals->array[i]->bus->link_id);
link_num = hweight32(link_mask);
- links = devm_kcalloc(sdev->dev, link_num, sizeof(*links), GFP_KERNEL);
+ /* An empty adr_link is needed to terminate the adr_link loop */
+ links = devm_kcalloc(sdev->dev, link_num + 1, sizeof(*links), GFP_KERNEL);
if (!links)
return NULL;
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
index 693d063830fa..38753b088fc1 100644
--- a/sound/soc/sof/sof-priv.h
+++ b/sound/soc/sof/sof-priv.h
@@ -17,6 +17,7 @@
#include <sound/sof/info.h>
#include <sound/sof/pm.h>
#include <sound/sof/trace.h>
+#include <sound/compress_params.h>
#include <uapi/sound/sof/fw.h>
#include <sound/sof/ext_manifest.h>
@@ -111,6 +112,7 @@ struct sof_compr_stream {
u32 sampling_rate;
u16 channels;
u16 sample_container_bytes;
+ struct snd_codec codec_params;
size_t posn_offset;
};
diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c
index 6d1ce030963c..45d35b887e4e 100644
--- a/sound/soc/sti/uniperif_player.c
+++ b/sound/soc/sti/uniperif_player.c
@@ -1028,8 +1028,13 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev,
return PTR_ERR(regmap);
}
- player->clk_sel = regmap_field_alloc(regmap, regfield[0]);
- player->valid_sel = regmap_field_alloc(regmap, regfield[1]);
+ player->clk_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[0]);
+ if (IS_ERR(player->clk_sel))
+ return PTR_ERR(player->clk_sel);
+
+ player->valid_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[1]);
+ if (IS_ERR(player->valid_sel))
+ return PTR_ERR(player->valid_sel);
return 0;
}
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index a8bddc90c0ed..13d7380bb392 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -1947,15 +1947,17 @@ static struct usb_ms_endpoint_descriptor *find_usb_ms_endpoint_descriptor(
while (extralen > 3) {
struct usb_ms_endpoint_descriptor *ms_ep =
(struct usb_ms_endpoint_descriptor *)extra;
+ int length = ms_ep->bLength;
- if (ms_ep->bLength > 3 &&
+ if (!length || length > extralen)
+ break;
+
+ if (length > 3 &&
ms_ep->bDescriptorType == USB_DT_CS_ENDPOINT &&
ms_ep->bDescriptorSubtype == UAC_MS_GENERAL)
return ms_ep;
- if (!extra[0])
- break;
- extralen -= extra[0];
- extra += extra[0];
+ extralen -= length;
+ extra += length;
}
return NULL;
}
diff --git a/sound/usb/midi2.c b/sound/usb/midi2.c
index d700022f3cf8..44d1deacacdf 100644
--- a/sound/usb/midi2.c
+++ b/sound/usb/midi2.c
@@ -496,15 +496,17 @@ static void *find_usb_ms_endpoint_descriptor(struct usb_host_endpoint *hostep,
while (extralen > 3) {
struct usb_ms_endpoint_descriptor *ms_ep =
(struct usb_ms_endpoint_descriptor *)extra;
+ int length = ms_ep->bLength;
- if (ms_ep->bLength > 3 &&
+ if (!length || length > extralen)
+ break;
+
+ if (length > 3 &&
ms_ep->bDescriptorType == USB_DT_CS_ENDPOINT &&
ms_ep->bDescriptorSubtype == subtype)
return ms_ep;
- if (!extra[0])
- break;
- extralen -= extra[0];
- extra += extra[0];
+ extralen -= length;
+ extra += length;
}
return NULL;
}
diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c
index fd1fb668929a..8eaa96222759 100644
--- a/sound/usb/mixer_scarlett2.c
+++ b/sound/usb/mixer_scarlett2.c
@@ -2262,7 +2262,7 @@ static const struct scarlett2_device_entry scarlett2_devices[] = {
{ USB_ID(0x1235, 0x820c), &clarett_8pre_info, "Clarett+" },
/* End of list */
- { 0, NULL },
+ { 0, NULL, NULL },
};
/* get the starting port index number for a given port type/direction */
diff --git a/sound/usb/qcom/qc_audio_offload.c b/sound/usb/qcom/qc_audio_offload.c
index 2ac813d57f4f..a0009503b2c5 100644
--- a/sound/usb/qcom/qc_audio_offload.c
+++ b/sound/usb/qcom/qc_audio_offload.c
@@ -565,6 +565,7 @@ static unsigned long uaudio_iommu_map_pa(enum mem_type mtype, bool dma_coherent,
unsigned long iova = 0;
bool map = true;
int prot = uaudio_iommu_map_prot(dma_coherent);
+ int ret;
switch (mtype) {
case MEM_EVENT_RING:
@@ -582,10 +583,24 @@ static unsigned long uaudio_iommu_map_pa(enum mem_type mtype, bool dma_coherent,
dev_err(uaudio_qdev->data->dev, "unknown mem type %d\n", mtype);
}
- if (!iova || !map)
+ if (!iova)
return 0;
- iommu_map(uaudio_qdev->data->domain, iova, pa, size, prot, GFP_KERNEL);
+ if (!map)
+ return iova;
+
+ ret = iommu_map(uaudio_qdev->data->domain, iova, pa, size, prot,
+ GFP_KERNEL);
+ if (ret) {
+ dev_err(uaudio_qdev->data->dev,
+ "failed to map %zu bytes at iova 0x%08lx: %d\n",
+ size, iova, ret);
+ if (mtype == MEM_XFER_RING)
+ uaudio_put_iova(iova, size,
+ &uaudio_qdev->xfer_ring_list,
+ &uaudio_qdev->xfer_ring_iova_size);
+ return 0;
+ }
return iova;
}
@@ -948,7 +963,7 @@ static int enable_audio_stream(struct snd_usb_substream *subs,
_snd_pcm_hw_params_any(¶ms);
m = hw_param_mask(¶ms, SNDRV_PCM_HW_PARAM_FORMAT);
- snd_mask_leave(m, pcm_format);
+ snd_mask_leave(m, (__force unsigned int)pcm_format);
i = hw_param_interval(¶ms, SNDRV_PCM_HW_PARAM_CHANNELS);
snd_interval_setinteger(i);
@@ -1054,15 +1069,17 @@ static int uaudio_transfer_buffer_setup(struct snd_usb_substream *subs,
if (!xfer_buf)
return -ENOMEM;
- dma_get_sgtable(subs->dev->bus->sysdev, &xfer_buf_sgt, xfer_buf,
- xfer_buf_dma, len);
+ ret = dma_get_sgtable(subs->dev->bus->sysdev, &xfer_buf_sgt, xfer_buf,
+ xfer_buf_dma, len);
+ if (ret)
+ goto free_xfer_buf;
/* map the physical buffer into sysdev as well */
xfer_buf_dma_sysdev = uaudio_iommu_map_xfer_buf(dma_coherent,
len, &xfer_buf_sgt);
if (!xfer_buf_dma_sysdev) {
ret = -ENOMEM;
- goto unmap_sync;
+ goto free_sgt;
}
mem_info->dma = xfer_buf_dma;
@@ -1073,7 +1090,9 @@ static int uaudio_transfer_buffer_setup(struct snd_usb_substream *subs,
return 0;
-unmap_sync:
+free_sgt:
+ sg_free_table(&xfer_buf_sgt);
+free_xfer_buf:
usb_free_coherent(subs->dev, len, xfer_buf, xfer_buf_dma);
return ret;
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 4cfa24c06fcd..e8ae3464887b 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -122,7 +122,7 @@ static int add_audio_stream_from_fixed_fmt(struct snd_usb_audio *chip,
snd_usb_audioformat_set_sync_ep(chip, fp);
- err = snd_usb_add_audio_stream(chip, stream, fp);
+ err = snd_usb_add_audio_stream(chip, stream, fp, NULL);
if (err < 0)
return err;
@@ -2435,6 +2435,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_VALIDATE_RATES),
DEVICE_FLG(0x1235, 0x8006, 0), /* Focusrite Scarlett 2i2 1st Gen */
DEVICE_FLG(0x1235, 0x800a, 0), /* Focusrite Scarlett 2i4 1st Gen */
+ DEVICE_FLG(0x1235, 0x800c, 0), /* Focusrite Scarlett 18i20 1st Gen */
DEVICE_FLG(0x1235, 0x8016, 0), /* Focusrite Scarlett 2i2 1st Gen */
DEVICE_FLG(0x1235, 0x801c, 0), /* Focusrite Scarlett Solo 1st Gen */
VENDOR_FLG(0x1235, /* Focusrite Novation */
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index b07e2ec661c1..03a939cdd07a 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -79,7 +79,7 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)
static void snd_usb_init_substream(struct snd_usb_stream *as,
int stream,
struct audioformat *fp,
- struct snd_usb_power_domain *pd)
+ struct snd_usb_power_domain **pdptr)
{
struct snd_usb_substream *subs = &as->substream[stream];
@@ -105,10 +105,11 @@ static void snd_usb_init_substream(struct snd_usb_stream *as,
if (fp->channels > subs->channels_max)
subs->channels_max = fp->channels;
- if (pd) {
- subs->str_pd = pd;
+ if (pdptr && *pdptr) {
+ subs->str_pd = *pdptr;
+ *pdptr = NULL; /* assigned */
/* Initialize Power Domain to idle status D1 */
- snd_usb_power_domain_set(subs->stream->chip, pd,
+ snd_usb_power_domain_set(subs->stream->chip, subs->str_pd,
UAC3_PD_STATE_D1);
}
@@ -486,11 +487,14 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor
* if not, create a new pcm stream. note, fp is added to the substream
* fmt_list and will be freed on the chip instance release. do not free
* fp or do remove it from the substream fmt_list to avoid double-free.
+ *
+ * pdptr is optional and can be NULL. When it's non-NULL and the PD gets
+ * assigned to the stream, *pdptr is cleared to NULL upon return.
*/
-static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
- int stream,
- struct audioformat *fp,
- struct snd_usb_power_domain *pd)
+int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
+ int stream,
+ struct audioformat *fp,
+ struct snd_usb_power_domain **pdptr)
{
struct snd_usb_stream *as;
@@ -523,7 +527,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
err = snd_pcm_new_stream(as->pcm, stream, 1);
if (err < 0)
return err;
- snd_usb_init_substream(as, stream, fp, pd);
+ snd_usb_init_substream(as, stream, fp, pdptr);
return add_chmap(as->pcm, stream, subs);
}
@@ -552,7 +556,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
else
strscpy(pcm->name, "USB Audio");
- snd_usb_init_substream(as, stream, fp, pd);
+ snd_usb_init_substream(as, stream, fp, pdptr);
/*
* Keep using head insertion for M-Audio Audiophile USB (tm) which has a
@@ -570,21 +574,6 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
return add_chmap(pcm, stream, &as->substream[stream]);
}
-int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
- int stream,
- struct audioformat *fp)
-{
- return __snd_usb_add_audio_stream(chip, stream, fp, NULL);
-}
-
-static int snd_usb_add_audio_stream_v3(struct snd_usb_audio *chip,
- int stream,
- struct audioformat *fp,
- struct snd_usb_power_domain *pd)
-{
- return __snd_usb_add_audio_stream(chip, stream, fp, pd);
-}
-
static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
struct usb_host_interface *alts,
int protocol, int iface_no)
@@ -1107,8 +1096,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
}
}
- if (pd)
- *pd_out = pd;
+ *pd_out = pd;
return fp;
}
@@ -1123,7 +1111,6 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
struct usb_interface_descriptor *altsd;
int i, altno, err, stream;
struct audioformat *fp = NULL;
- struct snd_usb_power_domain *pd = NULL;
bool set_iface_first;
int num, protocol;
@@ -1165,6 +1152,12 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
if (snd_usb_apply_interface_quirk(chip, iface_no, altno))
continue;
+ /* pd may be allocated at snd_usb_get_audioformat_uac3() and
+ * assigned at snd_usb_add_audio_stream(); otherwise it'll be
+ * freed automatically by cleanup at each loop.
+ */
+ struct snd_usb_power_domain *pd __free(kfree) = NULL;
+
/*
* Roland audio streaming interfaces are marked with protocols
* 0/1/2, but are UAC 1 compatible.
@@ -1220,23 +1213,16 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
*has_non_pcm = true;
if ((fp->fmt_type == UAC_FORMAT_TYPE_I) == non_pcm) {
audioformat_free(fp);
- kfree(pd);
fp = NULL;
- pd = NULL;
continue;
}
snd_usb_audioformat_set_sync_ep(chip, fp);
dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint);
- if (protocol == UAC_VERSION_3)
- err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd);
- else
- err = snd_usb_add_audio_stream(chip, stream, fp);
-
+ err = snd_usb_add_audio_stream(chip, stream, fp, &pd);
if (err < 0) {
audioformat_free(fp);
- kfree(pd);
return err;
}
diff --git a/sound/usb/stream.h b/sound/usb/stream.h
index d92e18d5818f..61b9a133da01 100644
--- a/sound/usb/stream.h
+++ b/sound/usb/stream.h
@@ -7,7 +7,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
int stream,
- struct audioformat *fp);
+ struct audioformat *fp,
+ struct snd_usb_power_domain **pdptr);
#endif /* __USBAUDIO_STREAM_H */
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index 1fbcb3ce74d2..f163a245837a 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -103,12 +103,18 @@ else
endif
endif
+ifeq ($(findstring -static,${LDFLAGS}),-static)
+ PKG_CONFIG += --static
+endif
+
all: $(FILES)
__BUILD = $(CC) $(CFLAGS) -MD -Wall -Werror -o $@ $(patsubst %.bin,%.c,$(@F)) $(LDFLAGS)
BUILD = $(__BUILD) > $(@:.bin=.make.output) 2>&1
BUILD_BFD = $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl
- BUILD_ALL = $(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -lslang $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -ldl -lz -llzma -lzstd -lssl
+ BUILD_ALL = $(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -lslang \
+ $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -ldl -lz -llzma -lzstd \
+ $(shell $(PKG_CONFIG) --libs --cflags openssl 2>/dev/null)
__BUILDXX = $(CXX) $(CXXFLAGS) -MD -Wall -Werror -o $@ $(patsubst %.bin,%.cpp,$(@F)) $(LDFLAGS)
BUILDXX = $(__BUILDXX) > $(@:.bin=.make.output) 2>&1
@@ -384,7 +390,7 @@ $(OUTPUT)test-libpfm4.bin:
$(BUILD) -lpfm
$(OUTPUT)test-libopenssl.bin:
- $(BUILD) -lssl
+ $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags openssl 2>/dev/null)
$(OUTPUT)test-bpftool-skeletons.bin:
$(SYSTEM_BPFTOOL) version | grep '^features:.*skeletons' \
diff --git a/tools/hv/Makefile b/tools/hv/Makefile
index 34ffcec264ab..016753f3dd7f 100644
--- a/tools/hv/Makefile
+++ b/tools/hv/Makefile
@@ -2,7 +2,7 @@
# Makefile for Hyper-V tools
include ../scripts/Makefile.include
-ARCH := $(shell uname -m 2>/dev/null)
+ARCH ?= $(shell uname -m 2>/dev/null)
sbindir ?= /usr/sbin
libexecdir ?= /usr/libexec
sharedstatedir ?= /var/lib
@@ -20,7 +20,7 @@ override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
override CFLAGS += -Wno-address-of-packed-member
ALL_TARGETS := hv_kvp_daemon hv_vss_daemon
-ifneq ($(ARCH), aarch64)
+ifneq ($(filter x86_64 x86,$(ARCH)),)
ALL_TARGETS += hv_fcopy_uio_daemon
endif
ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h
index a72506ceec6b..0c5818149f17 100644
--- a/tools/include/nolibc/arch-mips.h
+++ b/tools/include/nolibc/arch-mips.h
@@ -39,11 +39,19 @@
* - stack is 16-byte aligned
*/
+#if !defined(__mips_isa_rev) || __mips_isa_rev < 6
+#define _NOLIBC_SYSCALL_CLOBBER_HI_LO "hi", "lo"
+#else
+#define _NOLIBC_SYSCALL_CLOBBER_HI_LO "$0"
+#endif
+
#if defined(_ABIO32)
#define _NOLIBC_SYSCALL_CLOBBERLIST \
- "memory", "cc", "at", "v1", "hi", "lo", \
- "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"
+ "memory", "cc", "at", "v1", \
+ "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", \
+ _NOLIBC_SYSCALL_CLOBBER_HI_LO
+
#define _NOLIBC_SYSCALL_STACK_RESERVE "addiu $sp, $sp, -32\n"
#define _NOLIBC_SYSCALL_STACK_UNRESERVE "addiu $sp, $sp, 32\n"
@@ -52,7 +60,8 @@
/* binutils, GCC and clang disagree about register aliases, use numbers instead. */
#define _NOLIBC_SYSCALL_CLOBBERLIST \
"memory", "cc", "at", "v1", \
- "10", "11", "12", "13", "14", "15", "24", "25"
+ "10", "11", "12", "13", "14", "15", "24", "25", \
+ _NOLIBC_SYSCALL_CLOBBER_HI_LO
#define _NOLIBC_SYSCALL_STACK_RESERVE
#define _NOLIBC_SYSCALL_STACK_UNRESERVE
diff --git a/tools/include/nolibc/compiler.h b/tools/include/nolibc/compiler.h
index a8c7619dcdde..a8d5ca58dd63 100644
--- a/tools/include/nolibc/compiler.h
+++ b/tools/include/nolibc/compiler.h
@@ -47,6 +47,12 @@
# define __nolibc_fallthrough do { } while (0)
#endif /* __nolibc_has_attribute(fallthrough) */
+#if defined(__STDC_VERSION__)
+# define __nolibc_stdc_version __STDC_VERSION__
+#else
+# define __nolibc_stdc_version 0
+#endif
+
#define __nolibc_version(_major, _minor, _patch) ((_major) * 10000 + (_minor) * 100 + (_patch))
#ifdef __GNUC__
@@ -63,7 +69,7 @@
# define __nolibc_clang_version 0
#endif /* __clang__ */
-#if __STDC_VERSION__ >= 201112L || \
+#if __nolibc_stdc_version >= 201112L || \
__nolibc_gnuc_version >= __nolibc_version(4, 6, 0) || \
__nolibc_clang_version >= __nolibc_version(3, 0, 0)
# define __nolibc_static_assert(_t) _Static_assert(_t, "")
diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h
index 233318b0d0f0..a4df72d9a2d3 100644
--- a/tools/include/nolibc/stdio.h
+++ b/tools/include/nolibc/stdio.h
@@ -295,22 +295,31 @@ int fseek(FILE *stream, long offset, int whence)
* - %[l*]{d,u,c,x,p}
* - %s
* - unknown modifiers are ignored.
+ *
+ * Called by vfprintf() and snprintf() to do the actual formatting.
+ * The callers provide a callback function to save the formatted data.
+ * The callback function is called multiple times:
+ * - for each group of literal characters in the format string.
+ * - for field padding.
+ * - for each conversion specifier.
+ * - with (NULL, 0) at the end of the __nolibc_printf.
+ * If the callback returns non-zero __nolibc_printf() immediately returns -1.
*/
-typedef int (*__nolibc_printf_cb)(intptr_t state, const char *buf, size_t size);
+typedef int (*__nolibc_printf_cb)(void *state, const char *buf, size_t size);
-static __attribute__((unused, format(printf, 4, 0)))
-int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char *fmt, va_list args)
+static __attribute__((unused, format(printf, 3, 0)))
+int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list args)
{
- char escape, lpref, c;
+ char escape, lpref, ch;
unsigned long long v;
unsigned int written, width;
- size_t len, ofs, w;
- char tmpbuf[21];
+ size_t len, ofs;
+ char outbuf[21];
const char *outstr;
written = ofs = escape = lpref = 0;
while (1) {
- c = fmt[ofs++];
+ ch = fmt[ofs++];
width = 0;
if (escape) {
@@ -318,17 +327,17 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char
escape = 0;
/* width */
- while (c >= '0' && c <= '9') {
+ while (ch >= '0' && ch <= '9') {
width *= 10;
- width += c - '0';
+ width += ch - '0';
- c = fmt[ofs++];
+ ch = fmt[ofs++];
}
- if (c == 'c' || c == 'd' || c == 'u' || c == 'x' || c == 'p') {
- char *out = tmpbuf;
+ if (ch == 'c' || ch == 'd' || ch == 'u' || ch == 'x' || ch == 'p') {
+ char *out = outbuf;
- if (c == 'p')
+ if (ch == 'p')
v = va_arg(args, unsigned long);
else if (lpref) {
if (lpref > 1)
@@ -338,7 +347,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char
} else
v = va_arg(args, unsigned int);
- if (c == 'd') {
+ if (ch == 'd') {
/* sign-extend the value */
if (lpref == 0)
v = (long long)(int)v;
@@ -346,7 +355,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char
v = (long long)(long)v;
}
- switch (c) {
+ switch (ch) {
case 'c':
out[0] = v;
out[1] = 0;
@@ -365,30 +374,30 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char
u64toh_r(v, out);
break;
}
- outstr = tmpbuf;
+ outstr = outbuf;
}
- else if (c == 's') {
+ else if (ch == 's') {
outstr = va_arg(args, char *);
if (!outstr)
outstr="(null)";
}
- else if (c == 'm') {
+ else if (ch == 'm') {
#ifdef NOLIBC_IGNORE_ERRNO
outstr = "unknown error";
#else
outstr = strerror(errno);
#endif /* NOLIBC_IGNORE_ERRNO */
}
- else if (c == '%') {
+ else if (ch == '%') {
/* queue it verbatim */
continue;
}
else {
/* modifiers or final 0 */
- if (c == 'l') {
+ if (ch == 'l') {
/* long format prefix, maintain the escape */
lpref++;
- } else if (c == 'j') {
+ } else if (ch == 'j') {
lpref = 2;
}
escape = 1;
@@ -399,28 +408,24 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char
}
/* not an escape sequence */
- if (c == 0 || c == '%') {
+ if (ch == 0 || ch == '%') {
/* flush pending data on escape or end */
escape = 1;
lpref = 0;
outstr = fmt;
len = ofs - 1;
flush_str:
- if (n) {
- w = len < n ? len : n;
- n -= w;
- while (width-- > w) {
- if (cb(state, " ", 1) != 0)
- return -1;
- written += 1;
- }
- if (cb(state, outstr, w) != 0)
+ while (width-- > len) {
+ if (cb(state, " ", 1) != 0)
return -1;
+ written += 1;
}
+ if (cb(state, outstr, len) != 0)
+ return -1;
written += len;
do_escape:
- if (c == 0)
+ if (ch == 0)
break;
fmt += ofs;
ofs = 0;
@@ -429,18 +434,25 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char
/* literal char, just queue it */
}
+
+ /* Request a final '\0' be added to the snprintf() output.
+ * This may be the only call of the cb() function.
+ */
+ if (cb(state, NULL, 0) != 0)
+ return -1;
+
return written;
}
-static int __nolibc_fprintf_cb(intptr_t state, const char *buf, size_t size)
+static int __nolibc_fprintf_cb(void *stream, const char *buf, size_t size)
{
- return _fwrite(buf, size, (FILE *)state);
+ return _fwrite(buf, size, stream);
}
static __attribute__((unused, format(printf, 2, 0)))
int vfprintf(FILE *stream, const char *fmt, va_list args)
{
- return __nolibc_printf(__nolibc_fprintf_cb, (intptr_t)stream, SIZE_MAX, fmt, args);
+ return __nolibc_printf(__nolibc_fprintf_cb, stream, fmt, args);
}
static __attribute__((unused, format(printf, 1, 0)))
@@ -498,26 +510,54 @@ int dprintf(int fd, const char *fmt, ...)
return ret;
}
-static int __nolibc_sprintf_cb(intptr_t _state, const char *buf, size_t size)
+struct __nolibc_sprintf_cb_state {
+ char *buf;
+ size_t space;
+};
+
+static int __nolibc_sprintf_cb(void *v_state, const char *buf, size_t size)
{
- char **state = (char **)_state;
+ struct __nolibc_sprintf_cb_state *state = v_state;
+ size_t space = state->space;
+ char *tgt;
+
+ /* Truncate the request to fit in the output buffer space.
+ * The last byte is reserved for the terminating '\0'.
+ * state->space can only be zero for snprintf(NULL, 0, fmt, args)
+ * so this normally lets through calls with 'size == 0'.
+ */
+ if (size >= space) {
+ if (space <= 1)
+ return 0;
+ size = space - 1;
+ }
+ tgt = state->buf;
+
+ /* __nolibc_printf() ends with cb(state, NULL, 0) to request the output
+ * buffer be '\0' terminated.
+ * That will be the only cb() call for, eg, snprintf(buf, sz, "").
+ * Zero lengths can occur at other times (eg "%s" for an empty string).
+ * Unconditionally write the '\0' byte to reduce code size, it is
+ * normally overwritten by the data being output.
+ * There is no point adding a '\0' after copied data - there is always
+ * another call.
+ */
+ *tgt = '\0';
+ if (size) {
+ state->space = space - size;
+ state->buf = tgt + size;
+ memcpy(tgt, buf, size);
+ }
- memcpy(*state, buf, size);
- *state += size;
return 0;
}
static __attribute__((unused, format(printf, 3, 0)))
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
{
- char *state = buf;
- int ret;
+ struct __nolibc_sprintf_cb_state state = { .buf = buf, .space = size };
- ret = __nolibc_printf(__nolibc_sprintf_cb, (intptr_t)&state, size, fmt, args);
- if (ret < 0)
- return ret;
- buf[(size_t)ret < size ? (size_t)ret : size - 1] = '\0';
- return ret;
+ return __nolibc_printf(__nolibc_sprintf_cb, &state, fmt, args);
}
static __attribute__((unused, format(printf, 3, 4)))
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 0be7017800fe..ef7e7f3e31b7 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -5798,11 +5798,12 @@ static int load_module_btfs(struct bpf_object *obj)
info.name = ptr_to_u64(name);
info.name_len = sizeof(name);
+ btf = NULL;
err = bpf_btf_get_info_by_fd(fd, &info, &len);
if (err) {
err = -errno;
pr_warn("failed to get BTF object #%d info: %s\n", id, errstr(err));
- goto err_out;
+ break;
}
/* ignore non-module BTFs */
@@ -5816,15 +5817,15 @@ static int load_module_btfs(struct bpf_object *obj)
if (err) {
pr_warn("failed to load module [%s]'s BTF object #%d: %s\n",
name, id, errstr(err));
- goto err_out;
+ break;
}
err = libbpf_ensure_mem((void **)&obj->btf_modules, &obj->btf_module_cap,
sizeof(*obj->btf_modules), obj->btf_module_cnt + 1);
if (err)
- goto err_out;
+ break;
- mod_btf = &obj->btf_modules[obj->btf_module_cnt++];
+ mod_btf = &obj->btf_modules[obj->btf_module_cnt];
mod_btf->btf = btf;
mod_btf->id = id;
@@ -5832,16 +5833,16 @@ static int load_module_btfs(struct bpf_object *obj)
mod_btf->name = strdup(name);
if (!mod_btf->name) {
err = -ENOMEM;
- goto err_out;
+ break;
}
- continue;
+ obj->btf_module_cnt++;
+ }
-err_out:
+ if (err) {
+ btf__free(btf);
close(fd);
- return err;
}
-
- return 0;
+ return err;
}
static struct bpf_core_cand_list *
diff --git a/tools/lib/bpf/relo_core.c b/tools/lib/bpf/relo_core.c
index 6eea5edba58a..0ccc8f548cba 100644
--- a/tools/lib/bpf/relo_core.c
+++ b/tools/lib/bpf/relo_core.c
@@ -292,6 +292,8 @@ int bpf_core_parse_spec(const char *prog_name, const struct btf *btf,
++spec_str;
if (sscanf(spec_str, "%d%n", &access_idx, &parsed_len) != 1)
return -EINVAL;
+ if (access_idx < 0)
+ return -EINVAL;
if (spec->raw_len == BPF_CORE_SPEC_MAX_LEN)
return -E2BIG;
spec_str += parsed_len;
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index e8962c985d34..5585aeb97684 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -2250,7 +2250,7 @@ static int parse_map_entry(const struct option *opt, const char *str,
static int parse_max_stack(const struct option *opt, const char *str,
int unset __maybe_unused)
{
- unsigned long *len = (unsigned long *)opt->value;
+ int *len = opt->value;
long val;
char *endptr;
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 73c2ba7e3076..6a12c1068d8a 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -164,7 +164,7 @@ struct opt_aggr_mode {
};
/* Turn command line option into most generic aggregation mode setting. */
-static enum aggr_mode opt_aggr_mode_to_aggr_mode(struct opt_aggr_mode *opt_mode)
+static enum aggr_mode opt_aggr_mode_to_aggr_mode(const struct opt_aggr_mode *opt_mode)
{
enum aggr_mode mode = AGGR_GLOBAL;
@@ -1219,8 +1219,8 @@ static int parse_cache_level(const struct option *opt,
int unset __maybe_unused)
{
int level;
- struct opt_aggr_mode *opt_aggr_mode = (struct opt_aggr_mode *)opt->value;
- u32 *aggr_level = (u32 *)opt->data;
+ bool *per_cache = opt->value;
+ u32 *aggr_level = opt->data;
/*
* If no string is specified, aggregate based on the topology of
@@ -1258,7 +1258,7 @@ static int parse_cache_level(const struct option *opt,
return -EINVAL;
}
out:
- opt_aggr_mode->cache = true;
+ *per_cache = true;
*aggr_level = level;
return 0;
}
@@ -1917,25 +1917,33 @@ static int default_evlist_evsel_cmp(void *priv __maybe_unused,
const struct evsel *lhs = container_of(lhs_core, struct evsel, core);
const struct perf_evsel *rhs_core = container_of(r, struct perf_evsel, node);
const struct evsel *rhs = container_of(rhs_core, struct evsel, core);
+ const struct evsel *lhs_leader = evsel__leader(lhs);
+ const struct evsel *rhs_leader = evsel__leader(rhs);
- if (evsel__leader(lhs) == evsel__leader(rhs)) {
+ if (lhs_leader == rhs_leader) {
/* Within the same group, respect the original order. */
return lhs_core->idx - rhs_core->idx;
}
+ /*
+ * Compare using leader's attributes so that all members of a group
+ * stay together. This ensures leaders are opened before their members.
+ */
+
/* Sort default metrics evsels first, and default show events before those. */
- if (lhs->default_metricgroup != rhs->default_metricgroup)
- return lhs->default_metricgroup ? -1 : 1;
+ if (lhs_leader->default_metricgroup != rhs_leader->default_metricgroup)
+ return lhs_leader->default_metricgroup ? -1 : 1;
- if (lhs->default_show_events != rhs->default_show_events)
- return lhs->default_show_events ? -1 : 1;
+ if (lhs_leader->default_show_events != rhs_leader->default_show_events)
+ return lhs_leader->default_show_events ? -1 : 1;
/* Sort by PMU type (prefers legacy types first). */
- if (lhs->pmu != rhs->pmu)
- return lhs->pmu->type - rhs->pmu->type;
+ if (lhs_leader->pmu != rhs_leader->pmu)
+ return lhs_leader->pmu->type - rhs_leader->pmu->type;
- /* Sort by name. */
- return strcmp(evsel__name((struct evsel *)lhs), evsel__name((struct evsel *)rhs));
+ /* Sort by leader's name. */
+ return strcmp(evsel__name((struct evsel *)lhs_leader),
+ evsel__name((struct evsel *)rhs_leader));
}
/*
@@ -2305,24 +2313,23 @@ static struct perf_stat perf_stat = {
static int __cmd_report(int argc, const char **argv)
{
struct perf_session *session;
+ struct opt_aggr_mode opt_mode = {};
const struct option options[] = {
OPT_STRING('i', "input", &input_name, "file", "input file name"),
- OPT_SET_UINT(0, "per-socket", &perf_stat.aggr_mode,
- "aggregate counts per processor socket", AGGR_SOCKET),
- OPT_SET_UINT(0, "per-die", &perf_stat.aggr_mode,
- "aggregate counts per processor die", AGGR_DIE),
- OPT_SET_UINT(0, "per-cluster", &perf_stat.aggr_mode,
- "aggregate counts perf processor cluster", AGGR_CLUSTER),
- OPT_CALLBACK_OPTARG(0, "per-cache", &perf_stat.aggr_mode, &perf_stat.aggr_level,
- "cache level",
- "aggregate count at this cache level (Default: LLC)",
+ OPT_BOOLEAN(0, "per-thread", &opt_mode.thread, "aggregate counts per thread"),
+ OPT_BOOLEAN(0, "per-socket", &opt_mode.socket,
+ "aggregate counts per processor socket"),
+ OPT_BOOLEAN(0, "per-die", &opt_mode.die, "aggregate counts per processor die"),
+ OPT_BOOLEAN(0, "per-cluster", &opt_mode.cluster,
+ "aggregate counts per processor cluster"),
+ OPT_CALLBACK_OPTARG(0, "per-cache", &opt_mode.cache, &perf_stat.aggr_level,
+ "cache level", "aggregate count at this cache level (Default: LLC)",
parse_cache_level),
- OPT_SET_UINT(0, "per-core", &perf_stat.aggr_mode,
- "aggregate counts per physical processor core", AGGR_CORE),
- OPT_SET_UINT(0, "per-node", &perf_stat.aggr_mode,
- "aggregate counts per numa node", AGGR_NODE),
- OPT_SET_UINT('A', "no-aggr", &perf_stat.aggr_mode,
- "disable CPU count aggregation", AGGR_NONE),
+ OPT_BOOLEAN(0, "per-core", &opt_mode.core,
+ "aggregate counts per physical processor core"),
+ OPT_BOOLEAN(0, "per-node", &opt_mode.node, "aggregate counts per numa node"),
+ OPT_BOOLEAN('A', "no-aggr", &opt_mode.no_aggr,
+ "disable aggregation across CPUs or PMUs"),
OPT_END()
};
struct stat st;
@@ -2330,6 +2337,10 @@ static int __cmd_report(int argc, const char **argv)
argc = parse_options(argc, argv, options, stat_report_usage, 0);
+ perf_stat.aggr_mode = opt_aggr_mode_to_aggr_mode(&opt_mode);
+ if (perf_stat.aggr_mode == AGGR_GLOBAL)
+ perf_stat.aggr_mode = AGGR_UNSET; /* No option found so leave unset. */
+
if (!input_name || !strlen(input_name)) {
if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
input_name = "-";
@@ -2506,7 +2517,7 @@ int cmd_stat(int argc, const char **argv)
OPT_BOOLEAN(0, "per-die", &opt_mode.die, "aggregate counts per processor die"),
OPT_BOOLEAN(0, "per-cluster", &opt_mode.cluster,
"aggregate counts per processor cluster"),
- OPT_CALLBACK_OPTARG(0, "per-cache", &opt_mode, &stat_config.aggr_level,
+ OPT_CALLBACK_OPTARG(0, "per-cache", &opt_mode.cache, &stat_config.aggr_level,
"cache level", "aggregate count at this cache level (Default: LLC)",
parse_cache_level),
OPT_BOOLEAN(0, "per-core", &opt_mode.core,
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 311d9da9896a..7ff85fa90d98 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1565,7 +1565,9 @@ static bool syscall_id_equal(long key1, long key2, void *ctx __maybe_unused)
static struct hashmap *alloc_syscall_stats(void)
{
- return hashmap__new(syscall_id_hash, syscall_id_equal, NULL);
+ struct hashmap *result = hashmap__new(syscall_id_hash, syscall_id_equal, NULL);
+
+ return IS_ERR(result) ? NULL : result;
}
static void delete_syscall_stats(struct hashmap *syscall_stats)
@@ -1573,7 +1575,7 @@ static void delete_syscall_stats(struct hashmap *syscall_stats)
struct hashmap_entry *pos;
size_t bkt;
- if (syscall_stats == NULL)
+ if (!syscall_stats)
return;
hashmap__for_each_entry(syscall_stats, pos, bkt)
@@ -1589,7 +1591,7 @@ static struct thread_trace *thread_trace__new(struct trace *trace)
ttrace->files.max = -1;
if (trace->summary) {
ttrace->syscall_stats = alloc_syscall_stats();
- if (IS_ERR(ttrace->syscall_stats))
+ if (!ttrace->syscall_stats)
zfree(&ttrace);
}
}
@@ -4464,7 +4466,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
if (trace->summary_mode == SUMMARY__BY_TOTAL && !trace->summary_bpf) {
trace->syscall_stats = alloc_syscall_stats();
- if (IS_ERR(trace->syscall_stats))
+ if (!trace->syscall_stats)
goto out_delete_evlist;
}
@@ -4771,7 +4773,7 @@ static int trace__replay(struct trace *trace)
if (trace->summary_mode == SUMMARY__BY_TOTAL) {
trace->syscall_stats = alloc_syscall_stats();
- if (IS_ERR(trace->syscall_stats))
+ if (!trace->syscall_stats)
goto out;
}
diff --git a/tools/perf/pmu-events/arch/common/common/metrics.json b/tools/perf/pmu-events/arch/common/common/metrics.json
index 0d010b3ebc6d..cefc8bfe7830 100644
--- a/tools/perf/pmu-events/arch/common/common/metrics.json
+++ b/tools/perf/pmu-events/arch/common/common/metrics.json
@@ -46,14 +46,14 @@
},
{
"BriefDescription": "Max front or backend stalls per instruction",
- "MetricExpr": "max(stalled\\-cycles\\-frontend, stalled\\-cycles\\-backend) / instructions",
+ "MetricExpr": "(max(stalled\\-cycles\\-frontend, stalled\\-cycles\\-backend) / instructions) if (has_event(stalled\\-cycles\\-frontend) & has_event(stalled\\-cycles\\-backend)) else ((stalled\\-cycles\\-frontend / instructions) if has_event(stalled\\-cycles\\-frontend) else ((stalled\\-cycles\\-backend / instructions) if has_event(stalled\\-cycles\\-backend) else 0))",
"MetricGroup": "Default",
"MetricName": "stalled_cycles_per_instruction",
"DefaultShowEvents": "1"
},
{
"BriefDescription": "Frontend stalls per cycle",
- "MetricExpr": "stalled\\-cycles\\-frontend / cpu\\-cycles",
+ "MetricExpr": "(stalled\\-cycles\\-frontend / cpu\\-cycles) if has_event(stalled\\-cycles\\-frontend) else 0",
"MetricGroup": "Default",
"MetricName": "frontend_cycles_idle",
"MetricThreshold": "frontend_cycles_idle > 0.1",
@@ -61,7 +61,7 @@
},
{
"BriefDescription": "Backend stalls per cycle",
- "MetricExpr": "stalled\\-cycles\\-backend / cpu\\-cycles",
+ "MetricExpr": "(stalled\\-cycles\\-backend / cpu\\-cycles) if has_event(stalled\\-cycles\\-backend) else 0",
"MetricGroup": "Default",
"MetricName": "backend_cycles_idle",
"MetricThreshold": "backend_cycles_idle > 0.2",
diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index 76c395cf513c..a92dd0424f79 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -1310,33 +1310,33 @@ static const char *const big_c_string =
/* offset=128375 */ "migrations_per_second\000Default\000software@cpu\\-migrations\\,name\\=cpu\\-migrations@ * 1e9 / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Process migrations to a new CPU per CPU second\000\0001migrations/sec\000\000\000\000011"
/* offset=128635 */ "page_faults_per_second\000Default\000software@page\\-faults\\,name\\=page\\-faults@ * 1e9 / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Page faults per CPU second\000\0001faults/sec\000\000\000\000011"
/* offset=128866 */ "insn_per_cycle\000Default\000instructions / cpu\\-cycles\000insn_per_cycle < 1\000Instructions Per Cycle\000\0001instructions\000\000\000\000001"
-/* offset=128979 */ "stalled_cycles_per_instruction\000Default\000max(stalled\\-cycles\\-frontend, stalled\\-cycles\\-backend) / instructions\000\000Max front or backend stalls per instruction\000\000\000\000\000\000001"
-/* offset=129143 */ "frontend_cycles_idle\000Default\000stalled\\-cycles\\-frontend / cpu\\-cycles\000frontend_cycles_idle > 0.1\000Frontend stalls per cycle\000\000\000\000\000\000001"
-/* offset=129273 */ "backend_cycles_idle\000Default\000stalled\\-cycles\\-backend / cpu\\-cycles\000backend_cycles_idle > 0.2\000Backend stalls per cycle\000\000\000\000\000\000001"
-/* offset=129399 */ "cycles_frequency\000Default\000cpu\\-cycles / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Cycles per CPU second\000\0001GHz\000\000\000\000011"
-/* offset=129575 */ "branch_frequency\000Default\000branches / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Branches per CPU second\000\0001000M/sec\000\000\000\000011"
-/* offset=129755 */ "branch_miss_rate\000Default\000branch\\-misses / branches\000branch_miss_rate > 0.05\000Branch miss rate\000\000100%\000\000\000\000001"
-/* offset=129859 */ "l1d_miss_rate\000Default2\000L1\\-dcache\\-load\\-misses / L1\\-dcache\\-loads\000l1d_miss_rate > 0.05\000L1D miss rate\000\000100%\000\000\000\000001"
-/* offset=129975 */ "llc_miss_rate\000Default2\000LLC\\-load\\-misses / LLC\\-loads\000llc_miss_rate > 0.05\000LLC miss rate\000\000100%\000\000\000\000001"
-/* offset=130076 */ "l1i_miss_rate\000Default3\000L1\\-icache\\-load\\-misses / L1\\-icache\\-loads\000l1i_miss_rate > 0.05\000L1I miss rate\000\000100%\000\000\000\000001"
-/* offset=130191 */ "dtlb_miss_rate\000Default3\000dTLB\\-load\\-misses / dTLB\\-loads\000dtlb_miss_rate > 0.05\000dTLB miss rate\000\000100%\000\000\000\000001"
-/* offset=130297 */ "itlb_miss_rate\000Default3\000iTLB\\-load\\-misses / iTLB\\-loads\000itlb_miss_rate > 0.05\000iTLB miss rate\000\000100%\000\000\000\000001"
-/* offset=130403 */ "l1_prefetch_miss_rate\000Default4\000L1\\-dcache\\-prefetch\\-misses / L1\\-dcache\\-prefetches\000l1_prefetch_miss_rate > 0.05\000L1 prefetch miss rate\000\000100%\000\000\000\000001"
-/* offset=130551 */ "CPI\000\0001 / IPC\000\000\000\000\000\000\000\000000"
-/* offset=130574 */ "IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\000\000\000000"
-/* offset=130638 */ "Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.thread / 2 * (1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk)))\000\000\000\000\000\000\000\000000"
-/* offset=130805 */ "dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\000000"
-/* offset=130870 */ "icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\000000"
-/* offset=130938 */ "cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\000\000\000\000\000000"
-/* offset=131010 */ "DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit\000\000\000\000\000\000\000\000000"
-/* offset=131105 */ "DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss\000\000\000\000\000\000\000\000000"
-/* offset=131240 */ "DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000\000\000\000000"
-/* offset=131305 */ "DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000\000\000\000\000000"
-/* offset=131374 */ "DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\000\000\000\000\000000"
-/* offset=131445 */ "M1\000\000ipc + M2\000\000\000\000\000\000\000\000000"
-/* offset=131468 */ "M2\000\000ipc + M1\000\000\000\000\000\000\000\000000"
-/* offset=131491 */ "M3\000\0001 / M3\000\000\000\000\000\000\000\000000"
-/* offset=131512 */ "L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\000\000\000\000\000000"
+/* offset=128979 */ "stalled_cycles_per_instruction\000Default\000(max(stalled\\-cycles\\-frontend, stalled\\-cycles\\-backend) / instructions if has_event(stalled\\-cycles\\-frontend) & has_event(stalled\\-cycles\\-backend) else (stalled\\-cycles\\-frontend / instructions if has_event(stalled\\-cycles\\-frontend) else (stalled\\-cycles\\-backend / instructions if has_event(stalled\\-cycles\\-backend) else 0)))\000\000Max front or backend stalls per instruction\000\000\000\000\000\000001"
+/* offset=129404 */ "frontend_cycles_idle\000Default\000(stalled\\-cycles\\-frontend / cpu\\-cycles if has_event(stalled\\-cycles\\-frontend) else 0)\000frontend_cycles_idle > 0.1\000Frontend stalls per cycle\000\000\000\000\000\000001"
+/* offset=129583 */ "backend_cycles_idle\000Default\000(stalled\\-cycles\\-backend / cpu\\-cycles if has_event(stalled\\-cycles\\-backend) else 0)\000backend_cycles_idle > 0.2\000Backend stalls per cycle\000\000\000\000\000\000001"
+/* offset=129757 */ "cycles_frequency\000Default\000cpu\\-cycles / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Cycles per CPU second\000\0001GHz\000\000\000\000011"
+/* offset=129933 */ "branch_frequency\000Default\000branches / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Branches per CPU second\000\0001000M/sec\000\000\000\000011"
+/* offset=130113 */ "branch_miss_rate\000Default\000branch\\-misses / branches\000branch_miss_rate > 0.05\000Branch miss rate\000\000100%\000\000\000\000001"
+/* offset=130217 */ "l1d_miss_rate\000Default2\000L1\\-dcache\\-load\\-misses / L1\\-dcache\\-loads\000l1d_miss_rate > 0.05\000L1D miss rate\000\000100%\000\000\000\000001"
+/* offset=130333 */ "llc_miss_rate\000Default2\000LLC\\-load\\-misses / LLC\\-loads\000llc_miss_rate > 0.05\000LLC miss rate\000\000100%\000\000\000\000001"
+/* offset=130434 */ "l1i_miss_rate\000Default3\000L1\\-icache\\-load\\-misses / L1\\-icache\\-loads\000l1i_miss_rate > 0.05\000L1I miss rate\000\000100%\000\000\000\000001"
+/* offset=130549 */ "dtlb_miss_rate\000Default3\000dTLB\\-load\\-misses / dTLB\\-loads\000dtlb_miss_rate > 0.05\000dTLB miss rate\000\000100%\000\000\000\000001"
+/* offset=130655 */ "itlb_miss_rate\000Default3\000iTLB\\-load\\-misses / iTLB\\-loads\000itlb_miss_rate > 0.05\000iTLB miss rate\000\000100%\000\000\000\000001"
+/* offset=130761 */ "l1_prefetch_miss_rate\000Default4\000L1\\-dcache\\-prefetch\\-misses / L1\\-dcache\\-prefetches\000l1_prefetch_miss_rate > 0.05\000L1 prefetch miss rate\000\000100%\000\000\000\000001"
+/* offset=130909 */ "CPI\000\0001 / IPC\000\000\000\000\000\000\000\000000"
+/* offset=130932 */ "IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\000\000\000000"
+/* offset=130996 */ "Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.thread / 2 * (1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk)))\000\000\000\000\000\000\000\000000"
+/* offset=131163 */ "dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\000000"
+/* offset=131228 */ "icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\000000"
+/* offset=131296 */ "cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\000\000\000\000\000000"
+/* offset=131368 */ "DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit\000\000\000\000\000\000\000\000000"
+/* offset=131463 */ "DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss\000\000\000\000\000\000\000\000000"
+/* offset=131598 */ "DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000\000\000\000000"
+/* offset=131663 */ "DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000\000\000\000\000000"
+/* offset=131732 */ "DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\000\000\000\000\000000"
+/* offset=131803 */ "M1\000\000ipc + M2\000\000\000\000\000\000\000\000000"
+/* offset=131826 */ "M2\000\000ipc + M1\000\000\000\000\000\000\000\000000"
+/* offset=131849 */ "M3\000\0001 / M3\000\000\000\000\000\000\000\000000"
+/* offset=131870 */ "L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\000\000\000\000\000000"
;
static const struct compact_pmu_event pmu_events__common_default_core[] = {
@@ -2626,22 +2626,22 @@ static const struct pmu_table_entry pmu_events__common[] = {
static const struct compact_pmu_event pmu_metrics__common_default_core[] = {
{ 127956 }, /* CPUs_utilized\000Default\000(software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@) / (duration_time * 1e9)\000\000Average CPU utilization\000\0001CPUs\000\000\000\000011 */
-{ 129273 }, /* backend_cycles_idle\000Default\000stalled\\-cycles\\-backend / cpu\\-cycles\000backend_cycles_idle > 0.2\000Backend stalls per cycle\000\000\000\000\000\000001 */
-{ 129575 }, /* branch_frequency\000Default\000branches / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Branches per CPU second\000\0001000M/sec\000\000\000\000011 */
-{ 129755 }, /* branch_miss_rate\000Default\000branch\\-misses / branches\000branch_miss_rate > 0.05\000Branch miss rate\000\000100%\000\000\000\000001 */
+{ 129583 }, /* backend_cycles_idle\000Default\000(stalled\\-cycles\\-backend / cpu\\-cycles if has_event(stalled\\-cycles\\-backend) else 0)\000backend_cycles_idle > 0.2\000Backend stalls per cycle\000\000\000\000\000\000001 */
+{ 129933 }, /* branch_frequency\000Default\000branches / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Branches per CPU second\000\0001000M/sec\000\000\000\000011 */
+{ 130113 }, /* branch_miss_rate\000Default\000branch\\-misses / branches\000branch_miss_rate > 0.05\000Branch miss rate\000\000100%\000\000\000\000001 */
{ 128142 }, /* cs_per_second\000Default\000software@context\\-switches\\,name\\=context\\-switches@ * 1e9 / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Context switches per CPU second\000\0001cs/sec\000\000\000\000011 */
-{ 129399 }, /* cycles_frequency\000Default\000cpu\\-cycles / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Cycles per CPU second\000\0001GHz\000\000\000\000011 */
-{ 130191 }, /* dtlb_miss_rate\000Default3\000dTLB\\-load\\-misses / dTLB\\-loads\000dtlb_miss_rate > 0.05\000dTLB miss rate\000\000100%\000\000\000\000001 */
-{ 129143 }, /* frontend_cycles_idle\000Default\000stalled\\-cycles\\-frontend / cpu\\-cycles\000frontend_cycles_idle > 0.1\000Frontend stalls per cycle\000\000\000\000\000\000001 */
+{ 129757 }, /* cycles_frequency\000Default\000cpu\\-cycles / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Cycles per CPU second\000\0001GHz\000\000\000\000011 */
+{ 130549 }, /* dtlb_miss_rate\000Default3\000dTLB\\-load\\-misses / dTLB\\-loads\000dtlb_miss_rate > 0.05\000dTLB miss rate\000\000100%\000\000\000\000001 */
+{ 129404 }, /* frontend_cycles_idle\000Default\000(stalled\\-cycles\\-frontend / cpu\\-cycles if has_event(stalled\\-cycles\\-frontend) else 0)\000frontend_cycles_idle > 0.1\000Frontend stalls per cycle\000\000\000\000\000\000001 */
{ 128866 }, /* insn_per_cycle\000Default\000instructions / cpu\\-cycles\000insn_per_cycle < 1\000Instructions Per Cycle\000\0001instructions\000\000\000\000001 */
-{ 130297 }, /* itlb_miss_rate\000Default3\000iTLB\\-load\\-misses / iTLB\\-loads\000itlb_miss_rate > 0.05\000iTLB miss rate\000\000100%\000\000\000\000001 */
-{ 130403 }, /* l1_prefetch_miss_rate\000Default4\000L1\\-dcache\\-prefetch\\-misses / L1\\-dcache\\-prefetches\000l1_prefetch_miss_rate > 0.05\000L1 prefetch miss rate\000\000100%\000\000\000\000001 */
-{ 129859 }, /* l1d_miss_rate\000Default2\000L1\\-dcache\\-load\\-misses / L1\\-dcache\\-loads\000l1d_miss_rate > 0.05\000L1D miss rate\000\000100%\000\000\000\000001 */
-{ 130076 }, /* l1i_miss_rate\000Default3\000L1\\-icache\\-load\\-misses / L1\\-icache\\-loads\000l1i_miss_rate > 0.05\000L1I miss rate\000\000100%\000\000\000\000001 */
-{ 129975 }, /* llc_miss_rate\000Default2\000LLC\\-load\\-misses / LLC\\-loads\000llc_miss_rate > 0.05\000LLC miss rate\000\000100%\000\000\000\000001 */
+{ 130655 }, /* itlb_miss_rate\000Default3\000iTLB\\-load\\-misses / iTLB\\-loads\000itlb_miss_rate > 0.05\000iTLB miss rate\000\000100%\000\000\000\000001 */
+{ 130761 }, /* l1_prefetch_miss_rate\000Default4\000L1\\-dcache\\-prefetch\\-misses / L1\\-dcache\\-prefetches\000l1_prefetch_miss_rate > 0.05\000L1 prefetch miss rate\000\000100%\000\000\000\000001 */
+{ 130217 }, /* l1d_miss_rate\000Default2\000L1\\-dcache\\-load\\-misses / L1\\-dcache\\-loads\000l1d_miss_rate > 0.05\000L1D miss rate\000\000100%\000\000\000\000001 */
+{ 130434 }, /* l1i_miss_rate\000Default3\000L1\\-icache\\-load\\-misses / L1\\-icache\\-loads\000l1i_miss_rate > 0.05\000L1I miss rate\000\000100%\000\000\000\000001 */
+{ 130333 }, /* llc_miss_rate\000Default2\000LLC\\-load\\-misses / LLC\\-loads\000llc_miss_rate > 0.05\000LLC miss rate\000\000100%\000\000\000\000001 */
{ 128375 }, /* migrations_per_second\000Default\000software@cpu\\-migrations\\,name\\=cpu\\-migrations@ * 1e9 / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Process migrations to a new CPU per CPU second\000\0001migrations/sec\000\000\000\000011 */
{ 128635 }, /* page_faults_per_second\000Default\000software@page\\-faults\\,name\\=page\\-faults@ * 1e9 / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Page faults per CPU second\000\0001faults/sec\000\000\000\000011 */
-{ 128979 }, /* stalled_cycles_per_instruction\000Default\000max(stalled\\-cycles\\-frontend, stalled\\-cycles\\-backend) / instructions\000\000Max front or backend stalls per instruction\000\000\000\000\000\000001 */
+{ 128979 }, /* stalled_cycles_per_instruction\000Default\000(max(stalled\\-cycles\\-frontend, stalled\\-cycles\\-backend) / instructions if has_event(stalled\\-cycles\\-frontend) & has_event(stalled\\-cycles\\-backend) else (stalled\\-cycles\\-frontend / instructions if has_event(stalled\\-cycles\\-frontend) else (stalled\\-cycles\\-backend / instructions if has_event(stalled\\-cycles\\-backend) else 0)))\000\000Max front or backend stalls per instruction\000\000\000\000\000\000001 */
};
@@ -2714,21 +2714,21 @@ static const struct pmu_table_entry pmu_events__test_soc_cpu[] = {
};
static const struct compact_pmu_event pmu_metrics__test_soc_cpu_default_core[] = {
-{ 130551 }, /* CPI\000\0001 / IPC\000\000\000\000\000\000\000\000000 */
-{ 131240 }, /* DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000\000\000\000000 */
-{ 131010 }, /* DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit\000\000\000\000\000\000\000\000000 */
-{ 131105 }, /* DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss\000\000\000\000\000\000\000\000000 */
-{ 131305 }, /* DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000\000\000\000\000000 */
-{ 131374 }, /* DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\000\000\000\000\000000 */
-{ 130638 }, /* Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.thread / 2 * (1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk)))\000\000\000\000\000\000\000\000000 */
-{ 130574 }, /* IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\000\000\000000 */
-{ 131512 }, /* L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\000\000\000\000\000000 */
-{ 131445 }, /* M1\000\000ipc + M2\000\000\000\000\000\000\000\000000 */
-{ 131468 }, /* M2\000\000ipc + M1\000\000\000\000\000\000\000\000000 */
-{ 131491 }, /* M3\000\0001 / M3\000\000\000\000\000\000\000\000000 */
-{ 130938 }, /* cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\000\000\000\000\000000 */
-{ 130805 }, /* dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\000000 */
-{ 130870 }, /* icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\000000 */
+{ 130909 }, /* CPI\000\0001 / IPC\000\000\000\000\000\000\000\000000 */
+{ 131598 }, /* DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000\000\000\000000 */
+{ 131368 }, /* DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit\000\000\000\000\000\000\000\000000 */
+{ 131463 }, /* DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss\000\000\000\000\000\000\000\000000 */
+{ 131663 }, /* DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000\000\000\000\000000 */
+{ 131732 }, /* DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\000\000\000\000\000000 */
+{ 130996 }, /* Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.thread / 2 * (1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk)))\000\000\000\000\000\000\000\000000 */
+{ 130932 }, /* IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\000\000\000000 */
+{ 131870 }, /* L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\000\000\000\000\000000 */
+{ 131803 }, /* M1\000\000ipc + M2\000\000\000\000\000\000\000\000000 */
+{ 131826 }, /* M2\000\000ipc + M1\000\000\000\000\000\000\000\000000 */
+{ 131849 }, /* M3\000\0001 / M3\000\000\000\000\000\000\000\000000 */
+{ 131296 }, /* cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\000\000\000\000\000000 */
+{ 131163 }, /* dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\000000 */
+{ 131228 }, /* icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\000000 */
};
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 1d3cc224fbc2..05c3e899b425 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -1796,31 +1796,38 @@ static bool test__acr_valid(void)
static int test__ratio_to_prev(struct evlist *evlist)
{
- struct evsel *evsel;
+ struct evsel *evsel, *leader;
TEST_ASSERT_VAL("wrong number of entries", 2 * perf_pmus__num_core_pmus() == evlist->core.nr_entries);
- evlist__for_each_entry(evlist, evsel) {
- if (!perf_pmu__has_format(evsel->pmu, "acr_mask"))
- return TEST_OK;
-
- if (evsel == evlist__first(evlist)) {
- TEST_ASSERT_VAL("wrong config2", 0 == evsel->core.attr.config2);
- TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel));
- TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2);
- TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 0);
- TEST_ASSERT_EVSEL("unexpected event",
- evsel__match(evsel, HARDWARE, HW_CPU_CYCLES),
- evsel);
- } else {
- TEST_ASSERT_VAL("wrong config2", 0 == evsel->core.attr.config2);
- TEST_ASSERT_VAL("wrong leader", !evsel__is_group_leader(evsel));
- TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 0);
- TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1);
- TEST_ASSERT_EVSEL("unexpected event",
- evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS),
- evsel);
+ evlist__for_each_entry(evlist, evsel) {
+ if (evsel != evsel__leader(evsel) ||
+ !perf_pmu__has_format(evsel->pmu, "acr_mask")) {
+ continue;
}
+ leader = evsel;
+ /* cycles */
+ TEST_ASSERT_VAL("wrong config2", 0 == leader->core.attr.config2);
+ TEST_ASSERT_VAL("wrong core.nr_members", leader->core.nr_members == 2);
+ TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(leader) == 0);
+ TEST_ASSERT_EVSEL("unexpected event",
+ evsel__match(leader, HARDWARE, HW_CPU_CYCLES),
+ leader);
+ /*
+ * The period value gets configured within evlist__config,
+ * while this test executes only parse events method.
+ */
+ TEST_ASSERT_VAL("wrong period", 0 == leader->core.attr.sample_period);
+
+ /* instructions/period=200000,ratio-to-prev=2.0/ */
+ evsel = evsel__next(evsel);
+ TEST_ASSERT_VAL("wrong config2", 0 == evsel->core.attr.config2);
+ TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
+ TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 0);
+ TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1);
+ TEST_ASSERT_EVSEL("unexpected event",
+ evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS),
+ evsel);
/*
* The period value gets configured within evlist__config,
* while this test executes only parse events method.
diff --git a/tools/perf/tests/shell/data_type_profiling.sh b/tools/perf/tests/shell/data_type_profiling.sh
index 2a7f8f7c42d0..eca694600a04 100755
--- a/tools/perf/tests/shell/data_type_profiling.sh
+++ b/tools/perf/tests/shell/data_type_profiling.sh
@@ -8,13 +8,17 @@ set -e
# data type profiling manifestation
# Values in testtypes and testprogs should match
-testtypes=("# data-type: struct Buf" "# data-type: struct _buf")
+testtypes=("# data-type: struct Buf" "# data-type: struct buf")
testprogs=("perf test -w code_with_type" "perf test -w datasym")
err=0
perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
perfout=$(mktemp /tmp/__perf_test.perf.out.XXXXX)
+# Check for support of perf mem before trap handler
+perf mem record -o /dev/null -- true 2>&1 | \
+ grep -q "failed: no PMU supports the memory events" && exit 2
+
cleanup() {
rm -rf "${perfdata}" "${perfout}"
rm -rf "${perfdata}".old
diff --git a/tools/perf/tests/workloads/datasym.c b/tools/perf/tests/workloads/datasym.c
index 1d0b7d64e1ba..19242c7255c0 100644
--- a/tools/perf/tests/workloads/datasym.c
+++ b/tools/perf/tests/workloads/datasym.c
@@ -4,14 +4,14 @@
#include <linux/compiler.h>
#include "../tests.h"
-typedef struct _buf {
+struct buf {
char data1;
char reserved[55];
char data2;
-} buf __attribute__((aligned(64)));
+} __attribute__((aligned(64)));
/* volatile to try to avoid the compiler seeing reserved as unused. */
-static volatile buf workload_datasym_buf1 = {
+static volatile struct buf workload_datasym_buf1 = {
/* to have this in the data section */
.reserved[0] = 1,
};
diff --git a/tools/perf/util/branch.h b/tools/perf/util/branch.h
index 7429530fa774..a1d4736497c4 100644
--- a/tools/perf/util/branch.h
+++ b/tools/perf/util/branch.h
@@ -66,6 +66,9 @@ static inline struct branch_entry *perf_sample__branch_entries(struct perf_sampl
{
u64 *entry = (u64 *)sample->branch_stack;
+ if (entry == NULL)
+ return NULL;
+
entry++;
if (sample->no_hw_idx)
return (struct branch_entry *)entry;
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
index 040eb75f0804..1b5664d1481f 100644
--- a/tools/perf/util/cgroup.c
+++ b/tools/perf/util/cgroup.c
@@ -417,7 +417,6 @@ static bool has_pattern_string(const char *str)
int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgroup)
{
struct evlist *orig_list, *tmp_list;
- struct evsel *pos, *evsel, *leader;
struct rblist orig_metric_events;
struct cgroup *cgrp = NULL;
struct cgroup_name *cn;
@@ -452,6 +451,7 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgro
goto out_err;
list_for_each_entry(cn, &cgroup_list, list) {
+ struct evsel *pos;
char *name;
if (!cn->used)
@@ -467,21 +467,37 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgro
if (cgrp == NULL)
continue;
- leader = NULL;
+ /* copy the list and set to the new cgroup. */
evlist__for_each_entry(orig_list, pos) {
- evsel = evsel__clone(/*dest=*/NULL, pos);
+ struct evsel *evsel = evsel__clone(/*dest=*/NULL, pos);
+
if (evsel == NULL)
goto out_err;
+ /* stash the copy during the copying. */
+ pos->priv = evsel;
cgroup__put(evsel->cgrp);
evsel->cgrp = cgroup__get(cgrp);
- if (evsel__is_group_leader(pos))
- leader = evsel;
- evsel__set_leader(evsel, leader);
-
evlist__add(tmp_list, evsel);
}
+ /* update leader information using stashed pointer to copy. */
+ evlist__for_each_entry(orig_list, pos) {
+ struct evsel *evsel = pos->priv;
+
+ if (evsel__leader(pos))
+ evsel__set_leader(evsel, evsel__leader(pos)->priv);
+
+ if (pos->metric_leader)
+ evsel->metric_leader = pos->metric_leader->priv;
+
+ if (pos->first_wildcard_match)
+ evsel->first_wildcard_match = pos->first_wildcard_match->priv;
+ }
+ /* the stashed copy is no longer used. */
+ evlist__for_each_entry(orig_list, pos)
+ pos->priv = NULL;
+
/* cgroup__new() has a refcount, release it here */
cgroup__put(cgrp);
nr_cgroups++;
diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
index 212f17a3dc72..310af4075110 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
@@ -237,46 +237,24 @@ cs_etm_decoder__init_def_logger_printing(struct cs_etm_decoder_params *d_params,
(void *)decoder,
cs_etm_decoder__print_str_cb);
if (ret != 0)
- ret = -1;
-
- return 0;
-}
+ return -1;
#ifdef CS_LOG_RAW_FRAMES
-static void
-cs_etm_decoder__init_raw_frame_logging(struct cs_etm_decoder_params *d_params,
- struct cs_etm_decoder *decoder)
-{
- /* Only log these during a --dump operation */
- if (d_params->operation == CS_ETM_OPERATION_PRINT) {
- /* set up a library default logger to process the
- * raw frame printer we add later
- */
- ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR, 1);
-
- /* no stdout / err / file output */
- ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE, NULL);
-
- /* set the string CB for the default logger,
- * passes strings to perf print logger.
- */
- ocsd_def_errlog_set_strprint_cb(decoder->dcd_tree,
- (void *)decoder,
- cs_etm_decoder__print_str_cb);
-
+ /*
+ * Only log raw frames if --dump operation and hardware is actually
+ * generating formatted CoreSight trace frames
+ */
+ if ((d_params->operation == CS_ETM_OPERATION_PRINT) &&
+ (d_params->formatted == true)) {
/* use the built in library printer for the raw frames */
- ocsd_dt_set_raw_frame_printer(decoder->dcd_tree,
- CS_RAW_DEBUG_FLAGS);
+ ret = ocsd_dt_set_raw_frame_printer(decoder->dcd_tree,
+ CS_RAW_DEBUG_FLAGS);
+ if (ret != 0)
+ return -1;
}
-}
-#else
-static void
-cs_etm_decoder__init_raw_frame_logging(
- struct cs_etm_decoder_params *d_params __maybe_unused,
- struct cs_etm_decoder *decoder __maybe_unused)
-{
-}
#endif
+ return 0;
+}
static ocsd_datapath_resp_t
cs_etm_decoder__do_soft_timestamp(struct cs_etm_queue *etmq,
@@ -738,9 +716,6 @@ cs_etm_decoder__new(int decoders, struct cs_etm_decoder_params *d_params,
if (ret != 0)
goto err_free_decoder;
- /* init raw frame logging if required */
- cs_etm_decoder__init_raw_frame_logging(d_params, decoder);
-
for (i = 0; i < decoders; i++) {
ret = cs_etm_decoder__create_etm_decoder(d_params,
&t_params[i],
diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
index 465fe2e9bbbe..b7664cb68554 100644
--- a/tools/perf/util/expr.c
+++ b/tools/perf/util/expr.c
@@ -376,7 +376,8 @@ int expr__find_ids(const char *expr, const char *one,
if (one)
expr__del_id(ctx, one);
- return ret;
+ /* A positive value means syntax error, convert to -EINVAL */
+ return ret > 0 ? -EINVAL : ret;
}
double expr_id_data__value(const struct expr_id_data *data)
diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c
index 4092211cff62..75b399a20b26 100644
--- a/tools/perf/util/maps.c
+++ b/tools/perf/util/maps.c
@@ -956,6 +956,7 @@ static int __maps__fixup_overlap_and_insert(struct maps *maps, struct map *new)
if (maps_by_name) {
map__put(maps_by_name[ni]);
maps_by_name[ni] = map__get(new);
+ maps__set_maps_by_name_sorted(maps, false);
}
err = __maps__insert_sorted(maps, i + 1, after, NULL);
@@ -982,6 +983,7 @@ static int __maps__fixup_overlap_and_insert(struct maps *maps, struct map *new)
if (maps_by_name) {
map__put(maps_by_name[ni]);
maps_by_name[ni] = map__get(new);
+ maps__set_maps_by_name_sorted(maps, false);
}
check_invariants(maps);
@@ -1080,16 +1082,9 @@ int maps__copy_from(struct maps *dest, struct maps *parent)
map__put(new);
}
maps__set_maps_by_address_sorted(dest, maps__maps_by_address_sorted(parent));
- if (!err) {
- RC_CHK_ACCESS(dest)->last_search_by_name_idx =
- RC_CHK_ACCESS(parent)->last_search_by_name_idx;
- maps__set_maps_by_name_sorted(dest,
- dest_maps_by_name &&
- maps__maps_by_name_sorted(parent));
- } else {
- RC_CHK_ACCESS(dest)->last_search_by_name_idx = 0;
- maps__set_maps_by_name_sorted(dest, false);
- }
+ RC_CHK_ACCESS(dest)->last_search_by_name_idx = 0;
+ /* Values were copied into the name array in address order. */
+ maps__set_maps_by_name_sorted(dest, false);
} else {
/* Unexpected copying to a maps containing entries. */
for (unsigned int i = 0; !err && i < n; i++) {
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 76912c62b6a0..968e269d9be1 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1356,8 +1356,12 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map,
char dso_name[PATH_MAX];
/* Adjust symbol to map to file offset */
- if (adjust_kernel_syms)
- sym->st_value -= shdr->sh_addr - shdr->sh_offset;
+ if (adjust_kernel_syms) {
+ if (dso__rel(dso))
+ sym->st_value += shdr->sh_offset;
+ else
+ sym->st_value -= shdr->sh_addr - shdr->sh_offset;
+ }
if (strcmp(section_name, (dso__short_name(curr_dso) + dso__short_name_len(dso))) == 0)
return 0;
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 394dbfa944ac..e935438451b8 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -30,7 +30,6 @@ extern bool perf_guest;
/* General helper functions */
void usage(const char *err) __noreturn;
-void die(const char *err, ...) __noreturn __printf(1, 2);
struct dirent;
struct strlist;
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index e9e8ef72395a..e609272ed80b 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -2427,11 +2427,17 @@ char *sys_lpi_file_debugfs = "/sys/kernel/debug/pmc_core/slp_s0_residency_usec";
int cpu_is_not_present(int cpu)
{
+ if (cpu < 0)
+ return 1;
+
return !CPU_ISSET_S(cpu, cpu_present_setsize, cpu_present_set);
}
int cpu_is_not_allowed(int cpu)
{
+ if (cpu < 0)
+ return 1;
+
return !CPU_ISSET_S(cpu, cpu_allowed_setsize, cpu_allowed_set);
}
@@ -2443,6 +2449,22 @@ int cpu_is_not_allowed(int cpu)
#define PER_THREAD_PARAMS struct thread_data *t, struct core_data *c, struct pkg_data *p
+int has_allowed_lower_ht_sibling(int cpu)
+{
+ int i;
+
+ for (i = 0; i <= cpus[cpu].ht_id; ++i) {
+ int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i];
+
+ if (sibling_cpu_id == cpu)
+ return 0;
+
+ if (!cpu_is_not_allowed(sibling_cpu_id))
+ return 1;
+ }
+ return 0;
+}
+
int for_all_cpus(int (func) (struct thread_data *, struct core_data *, struct pkg_data *),
struct thread_data *thread_base, struct core_data *core_base, struct pkg_data *pkg_base)
{
@@ -2460,7 +2482,7 @@ int for_all_cpus(int (func) (struct thread_data *, struct core_data *, struct pk
if (cpu_is_not_allowed(cpu))
continue;
- if (cpus[cpu].ht_id > 0) /* skip HT sibling */
+ if (has_allowed_lower_ht_sibling(cpu)) /* skip HT sibling */
continue;
t = &thread_base[cpu];
@@ -2469,13 +2491,22 @@ int for_all_cpus(int (func) (struct thread_data *, struct core_data *, struct pk
retval |= func(t, c, p);
- /* Handle HT sibling now */
+ /* Handle other HT siblings now */
int i;
- for (i = MAX_HT_ID; i > 0; --i) { /* ht_id 0 is self */
- if (cpus[cpu].ht_sibling_cpu_id[i] <= 0)
+ for (i = 0; i <= MAX_HT_ID; ++i) {
+ int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i];
+
+ if (sibling_cpu_id < 0)
+ break;
+
+ if (sibling_cpu_id == cpu)
continue;
- t = &thread_base[cpus[cpu].ht_sibling_cpu_id[i]];
+
+ if (cpu_is_not_allowed(sibling_cpu_id))
+ continue;
+
+ t = &thread_base[sibling_cpu_id];
retval |= func(t, c, p);
}
@@ -5155,7 +5186,7 @@ static inline int get_rapl_num_domains(void)
if (!platform->has_per_core_rapl)
return topo.num_packages;
- return topo.num_cores;
+ return GLOBAL_CORE_ID(topo.max_core_id, topo.num_packages) + 1;
}
static inline int get_rapl_domain_id(int cpu)
@@ -6169,11 +6200,11 @@ int set_thread_siblings(struct cpu_topology *thiscpu)
int cpu = thiscpu->cpu_id;
int offset = topo.max_cpu_num + 1;
size_t size;
- int thread_id = 0;
+ int ht_id = 0;
thiscpu->put_ids = CPU_ALLOC((topo.max_cpu_num + 1));
if (thiscpu->ht_id < 0)
- thiscpu->ht_id = thread_id++;
+ thiscpu->ht_id = 0; /* first CPU in core */
if (!thiscpu->put_ids)
return -1;
@@ -6197,13 +6228,9 @@ int set_thread_siblings(struct cpu_topology *thiscpu)
sib_core = get_core_id(so);
if (sib_core == thiscpu->core_id) {
CPU_SET_S(so, size, thiscpu->put_ids);
- if ((so != cpu) && (cpus[so].ht_id < 0)) {
- cpus[so].ht_id = thread_id;
- cpus[cpu].ht_sibling_cpu_id[thread_id] = so;
- if (debug)
- fprintf(stderr, "%s: cpu%d.ht_sibling_cpu_id[%d] = %d\n", __func__, cpu, thread_id, so);
- thread_id += 1;
- }
+ cpus[so].ht_id = ht_id;
+ cpus[cpu].ht_sibling_cpu_id[ht_id] = so;
+ ht_id += 1;
}
}
}
@@ -6236,7 +6263,7 @@ int for_all_cpus_2(int (func) (struct thread_data *, struct core_data *,
if (cpu_is_not_allowed(cpu))
continue;
- if (cpus[cpu].ht_id > 0) /* skip HT sibling */
+ if (has_allowed_lower_ht_sibling(cpu)) /* skip HT sibling */
continue;
t = &thread_base[cpu];
@@ -6251,11 +6278,20 @@ int for_all_cpus_2(int (func) (struct thread_data *, struct core_data *,
/* Handle HT sibling now */
int i;
- for (i = MAX_HT_ID; i > 0; --i) { /* ht_id 0 is self */
- if (cpus[cpu].ht_sibling_cpu_id[i] <= 0)
+ for (i = 0; i <= MAX_HT_ID; ++i) {
+ int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i];
+
+ if (sibling_cpu_id < 0)
+ break;
+
+ if (sibling_cpu_id == cpu)
continue;
- t = &thread_base[cpus[cpu].ht_sibling_cpu_id[i]];
- t2 = &thread_base2[cpus[cpu].ht_sibling_cpu_id[i]];
+
+ if (cpu_is_not_allowed(sibling_cpu_id))
+ continue;
+
+ t = &thread_base[sibling_cpu_id];
+ t2 = &thread_base2[sibling_cpu_id];
retval |= func(t, c, p, t2, c2, p2);
}
@@ -9505,6 +9541,8 @@ void topology_probe(bool startup)
cpu_present_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
CPU_ZERO_S(cpu_present_setsize, cpu_present_set);
for_all_proc_cpus(mark_cpu_present);
+ if (debug)
+ print_cpu_set("present set", cpu_present_set);
/*
* Allocate and initialize cpu_possible_set
@@ -9515,6 +9553,8 @@ void topology_probe(bool startup)
cpu_possible_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
CPU_ZERO_S(cpu_possible_setsize, cpu_possible_set);
initialize_cpu_set_from_sysfs(cpu_possible_set, "/sys/devices/system/cpu", "possible");
+ if (debug)
+ print_cpu_set("possible set", cpu_possible_set);
/*
* Allocate and initialize cpu_effective_set
@@ -9525,6 +9565,8 @@ void topology_probe(bool startup)
cpu_effective_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
CPU_ZERO_S(cpu_effective_setsize, cpu_effective_set);
update_effective_set(startup);
+ if (debug)
+ print_cpu_set("effective set", cpu_effective_set);
/*
* Allocate and initialize cpu_allowed_set
@@ -9568,6 +9610,8 @@ void topology_probe(bool startup)
CPU_SET_S(i, cpu_allowed_setsize, cpu_allowed_set);
}
+ if (debug)
+ print_cpu_set("allowed set", cpu_allowed_set);
if (!CPU_COUNT_S(cpu_allowed_setsize, cpu_allowed_set))
err(-ENODEV, "No valid cpus found");
@@ -9671,12 +9715,18 @@ void topology_probe(bool startup)
return;
for (i = 0; i <= topo.max_cpu_num; ++i) {
+ int ht_id;
+
if (cpu_is_not_present(i))
continue;
fprintf(outf,
- "cpu %d pkg %d die %d l3 %d node %d lnode %d core %d thread %d\n",
+ "cpu %d pkg %d die %d l3 %d node %d lnode %d core %d ht_id %d",
i, cpus[i].package_id, cpus[i].die_id, cpus[i].l3_id,
cpus[i].physical_node_id, cpus[i].logical_node_id, cpus[i].core_id, cpus[i].ht_id);
+ fprintf(outf, " siblings");
+ for (ht_id = 0; ht_id <= MAX_HT_ID; ++ht_id)
+ fprintf(outf, " %d", cpus[i].ht_sibling_cpu_id[ht_id]);
+ fprintf(outf, "\n");
}
}
@@ -9817,6 +9867,8 @@ void topology_update(void)
topo.allowed_cores = 0;
topo.allowed_packages = 0;
for_all_cpus(update_topo, ODD_COUNTERS);
+ if (debug)
+ fprintf(stderr, "allowed_cpus %d allowed_cores %d allowed_packages %d\n", topo.allowed_cpus, topo.allowed_cores, topo.allowed_packages);
}
void setup_all_buffers(bool startup)
@@ -11449,7 +11501,7 @@ void cmdline(int argc, char **argv)
}
optind = 0;
- while ((opt = getopt_long_only(argc, argv, "+C:c:Dde:hi:Jn:N:o:qMST:v", long_options, &option_index)) != -1) {
+ while ((opt = getopt_long_only(argc, argv, "+C:c:Dde:hi:Jn:N:o:qMPST:v", long_options, &option_index)) != -1) {
switch (opt) {
case 'a':
parse_add_command(optarg);
diff --git a/tools/sched_ext/scx_pair.c b/tools/sched_ext/scx_pair.c
index 2e509391f3da..eb1bea2dd0cc 100644
--- a/tools/sched_ext/scx_pair.c
+++ b/tools/sched_ext/scx_pair.c
@@ -48,6 +48,7 @@ int main(int argc, char **argv)
struct bpf_link *link;
__u64 seq = 0, ecode;
__s32 stride, i, opt, outer_fd;
+ __u32 pair_id = 0;
libbpf_set_print(libbpf_print_fn);
signal(SIGINT, sigint_handler);
@@ -82,6 +83,14 @@ int main(int argc, char **argv)
scx_pair__destroy(skel);
return -1;
}
+
+ if (skel->rodata->nr_cpu_ids & 1) {
+ fprintf(stderr, "scx_pair requires an even CPU count, got %u\n",
+ skel->rodata->nr_cpu_ids);
+ scx_pair__destroy(skel);
+ return -1;
+ }
+
bpf_map__set_max_entries(skel->maps.pair_ctx, skel->rodata->nr_cpu_ids / 2);
/* Resize arrays so their element count is equal to cpu count. */
@@ -109,10 +118,11 @@ int main(int argc, char **argv)
skel->rodata_pair_cpu->pair_cpu[i] = j;
skel->rodata_pair_cpu->pair_cpu[j] = i;
- skel->rodata_pair_id->pair_id[i] = i;
- skel->rodata_pair_id->pair_id[j] = i;
+ skel->rodata_pair_id->pair_id[i] = pair_id;
+ skel->rodata_pair_id->pair_id[j] = pair_id;
skel->rodata_in_pair_idx->in_pair_idx[i] = 0;
skel->rodata_in_pair_idx->in_pair_idx[j] = 1;
+ pair_id++;
printf("[%d, %d] ", i, j);
}
diff --git a/tools/sched_ext/scx_sdt.bpf.c b/tools/sched_ext/scx_sdt.bpf.c
index 31b09958e8d5..2e2179d0f509 100644
--- a/tools/sched_ext/scx_sdt.bpf.c
+++ b/tools/sched_ext/scx_sdt.bpf.c
@@ -317,7 +317,8 @@ int scx_alloc_free_idx(struct scx_allocator *alloc, __u64 idx)
};
/* Zero out one word at a time. */
- for (i = zero; i < alloc->pool.elem_size / 8 && can_loop; i++) {
+ for (i = zero; i < (alloc->pool.elem_size - sizeof(struct sdt_data)) / 8
+ && can_loop; i++) {
data->payload[i] = 0;
}
}
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index 88de775097fe..17bdce9cafac 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -100,6 +100,7 @@ my $test_type;
my $build_type;
my $build_options;
my $final_post_ktest;
+my $post_ktest_done = 0;
my $pre_ktest;
my $post_ktest;
my $pre_test;
@@ -1575,6 +1576,24 @@ sub get_test_name() {
return $name;
}
+sub run_post_ktest {
+ my $cmd;
+
+ return if ($post_ktest_done);
+
+ if (defined($final_post_ktest)) {
+ $cmd = $final_post_ktest;
+ } elsif (defined($post_ktest)) {
+ $cmd = $post_ktest;
+ } else {
+ return;
+ }
+
+ my $cp_post_ktest = eval_kernel_version($cmd);
+ run_command $cp_post_ktest;
+ $post_ktest_done = 1;
+}
+
sub dodie {
# avoid recursion
return if ($in_die);
@@ -1634,6 +1653,7 @@ sub dodie {
if (defined($post_test)) {
run_command $post_test;
}
+ run_post_ktest;
die @_, "\n";
}
@@ -2508,7 +2528,7 @@ sub check_buildlog {
my $save_no_reboot = $no_reboot;
$no_reboot = 1;
- if (-f $warnings_file) {
+ if (defined($warnings_file) && -f $warnings_file) {
open(IN, $warnings_file) or
dodie "Error opening $warnings_file";
@@ -4183,7 +4203,8 @@ sub __set_test_option {
my $option = "$name\[$i\]";
- if (option_defined($option)) {
+ if (exists($opt{$option})) {
+ return undef if (!option_defined($option));
return $opt{$option};
}
@@ -4191,7 +4212,8 @@ sub __set_test_option {
if ($i >= $test &&
$i < $test + $repeat_tests{$test}) {
$option = "$name\[$test\]";
- if (option_defined($option)) {
+ if (exists($opt{$option})) {
+ return undef if (!option_defined($option));
return $opt{$option};
}
}
@@ -4298,6 +4320,7 @@ sub cancel_test {
send_email("KTEST: Your [$name] test was cancelled",
"Your test started at $script_start_time was cancelled: sig int");
}
+ run_post_ktest;
die "\nCaught Sig Int, test interrupted: $!\n"
}
@@ -4659,11 +4682,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
success $i;
}
-if (defined($final_post_ktest)) {
-
- my $cp_final_post_ktest = eval_kernel_version $final_post_ktest;
- run_command $cp_final_post_ktest;
-}
+run_post_ktest;
if ($opt{"POWEROFF_ON_SUCCESS"}) {
halt;
diff --git a/tools/testing/selftests/arm64/gcs/gcs-util.h b/tools/testing/selftests/arm64/gcs/gcs-util.h
index c99a6b39ac14..7a81bb07ed4b 100644
--- a/tools/testing/selftests/arm64/gcs/gcs-util.h
+++ b/tools/testing/selftests/arm64/gcs/gcs-util.h
@@ -18,12 +18,6 @@
#ifndef NT_ARM_GCS
#define NT_ARM_GCS 0x410
-
-struct user_gcs {
- __u64 features_enabled;
- __u64 features_locked;
- __u64 gcspr_el0;
-};
#endif
/* Shadow Stack/Guarded Control Stack interface */
diff --git a/tools/testing/selftests/arm64/gcs/libc-gcs.c b/tools/testing/selftests/arm64/gcs/libc-gcs.c
index 17b2fabfec38..72e82bfbecc9 100644
--- a/tools/testing/selftests/arm64/gcs/libc-gcs.c
+++ b/tools/testing/selftests/arm64/gcs/libc-gcs.c
@@ -16,6 +16,7 @@
#include <asm/hwcap.h>
#include <asm/mman.h>
+#include <asm/ptrace.h>
#include <linux/compiler.h>
diff --git a/tools/testing/selftests/bpf/prog_tests/access_variable_array.c b/tools/testing/selftests/bpf/prog_tests/access_variable_array.c
deleted file mode 100644
index 08131782437c..000000000000
--- a/tools/testing/selftests/bpf/prog_tests/access_variable_array.c
+++ /dev/null
@@ -1,16 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Copyright (c) 2022 Bytedance */
-
-#include <test_progs.h>
-#include "test_access_variable_array.skel.h"
-
-void test_access_variable_array(void)
-{
- struct test_access_variable_array *skel;
-
- skel = test_access_variable_array__open_and_load();
- if (!ASSERT_OK_PTR(skel, "test_access_variable_array__open_and_load"))
- return;
-
- test_access_variable_array__destroy(skel);
-}
diff --git a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c
index cb8dd2f63296..05fc9a7cf7c9 100644
--- a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c
+++ b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c
@@ -500,6 +500,39 @@ static struct range range_refine(enum num_t x_t, struct range x, enum num_t y_t,
(s64)x.a >= S32_MIN && (s64)x.b <= S32_MAX)
return range_intersection(x_t, x, y_cast);
+ if (y_t == U32 && x_t == U64) {
+ u64 xmin_swap, xmax_swap, xmin_lower32, xmax_lower32;
+
+ xmin_lower32 = x.a & 0xffffffff;
+ xmax_lower32 = x.b & 0xffffffff;
+ if (xmin_lower32 < y.a || xmin_lower32 > y.b) {
+ /* The 32 lower bits of the umin64 are outside the u32
+ * range. Let's update umin64 to match the u32 range.
+ * We want to *increase* the umin64 to the *minimum*
+ * value that matches the u32 range.
+ */
+ xmin_swap = swap_low32(x.a, y.a);
+ /* We should always only increase the minimum, so if
+ * the new value is lower than before, we need to
+ * increase the 32 upper bits by 1.
+ */
+ if (xmin_swap < x.a)
+ xmin_swap += 0x100000000;
+ if (xmin_swap == x.b)
+ return range(x_t, x.b, x.b);
+ } else if (xmax_lower32 < y.a || xmax_lower32 > y.b) {
+ /* Same for the umax64, but we want to *decrease*
+ * umax64 to the *maximum* value that matches the u32
+ * range.
+ */
+ xmax_swap = swap_low32(x.b, y.b);
+ if (xmax_swap > x.b)
+ xmax_swap -= 0x100000000;
+ if (xmax_swap == x.a)
+ return range(x_t, x.a, x.a);
+ }
+ }
+
/* the case when new range knowledge, *y*, is a 32-bit subregister
* range, while previous range knowledge, *x*, is a full register
* 64-bit range, needs special treatment to take into account upper 32
@@ -2129,6 +2162,8 @@ static struct subtest_case crafted_cases[] = {
{U64, S64, {0x7fffffff00000001ULL, 0xffffffff00000000ULL}, {0, 0}},
{U64, S64, {0, 0xffffffffULL}, {1, 1}},
{U64, S64, {0, 0xffffffffULL}, {0x7fffffff, 0x7fffffff}},
+ {U64, S32, {0xfffffffe00000001, 0xffffffff00000000}, {S64_MIN, S64_MIN}},
+ {U64, U32, {0xfffffffe00000000, U64_MAX - 1}, {U64_MAX, U64_MAX}},
{U64, U32, {0, 0x100000000}, {0, 0}},
{U64, U32, {0xfffffffe, 0x300000000}, {0x80000000, 0x80000000}},
diff --git a/tools/testing/selftests/bpf/prog_tests/snprintf.c b/tools/testing/selftests/bpf/prog_tests/snprintf.c
index 594441acb707..4e4a82d54f79 100644
--- a/tools/testing/selftests/bpf/prog_tests/snprintf.c
+++ b/tools/testing/selftests/bpf/prog_tests/snprintf.c
@@ -114,7 +114,8 @@ static void test_snprintf_negative(void)
ASSERT_ERR(load_single_snprintf("%--------"), "invalid specifier 5");
ASSERT_ERR(load_single_snprintf("%lc"), "invalid specifier 6");
ASSERT_ERR(load_single_snprintf("%llc"), "invalid specifier 7");
- ASSERT_ERR(load_single_snprintf("\x80"), "non ascii character");
+ ASSERT_OK(load_single_snprintf("\x80"), "non ascii plain text");
+ ASSERT_ERR(load_single_snprintf("%\x80"), "non ascii in specifier");
ASSERT_ERR(load_single_snprintf("\x1"), "non printable character");
ASSERT_ERR(load_single_snprintf("%p%"), "invalid specifier 8");
ASSERT_ERR(load_single_snprintf("%s%"), "invalid specifier 9");
diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
index dd3c757859f6..d2846579285f 100644
--- a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
+++ b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
@@ -1298,10 +1298,23 @@ static void test_sockmap_multi_channels(int sotype)
avail = wait_for_fionread(p1, expected, IO_TIMEOUT_SEC);
ASSERT_EQ(avail, expected, "ioctl(FIONREAD) full return");
- recvd = recv_timeout(p1, rcv, sizeof(rcv), MSG_DONTWAIT, 1);
- if (!ASSERT_EQ(recvd, sizeof(buf), "recv_timeout(p1)") ||
+ recvd = recv_timeout(p1, rcv, expected, MSG_DONTWAIT, 1);
+ if (!ASSERT_EQ(recvd, expected, "recv_timeout(p1)") ||
!ASSERT_OK(memcmp(buf, rcv, recvd), "data mismatch"))
goto end;
+
+ /* process remaining data for udp if secondary data is available */
+ expected = sizeof(buf) - expected;
+ if (expected) {
+ avail = wait_for_fionread(p1, expected, IO_TIMEOUT_SEC);
+ ASSERT_EQ(avail, expected, "second ioctl(FIONREAD) full return");
+
+ recvd = recv_timeout(p1, rcv, expected, MSG_DONTWAIT, 1);
+ if (!ASSERT_EQ(recvd, expected, "second recv_timeout(p1)") ||
+ !ASSERT_OK(memcmp(buf + sizeof(buf) - expected, rcv, recvd),
+ "second data mismatch"))
+ goto end;
+ }
end:
if (c0 >= 0)
close(c0);
diff --git a/tools/testing/selftests/bpf/prog_tests/test_bpf_smc.c b/tools/testing/selftests/bpf/prog_tests/test_bpf_smc.c
index de22734abc4d..40d38280c091 100644
--- a/tools/testing/selftests/bpf/prog_tests/test_bpf_smc.c
+++ b/tools/testing/selftests/bpf/prog_tests/test_bpf_smc.c
@@ -131,8 +131,10 @@ static bool get_smc_nl_family_id(void)
goto fail;
ret = recv(fd, &msg, sizeof(msg), 0);
- if (!ASSERT_FALSE(msg.n.nlmsg_type == NLMSG_ERROR || ret < 0 ||
- !NLMSG_OK(&msg.n, ret), "nl_family response"))
+ if (msg.n.nlmsg_type == NLMSG_ERROR)
+ goto fail;
+ if (!ASSERT_FALSE(ret < 0 || !NLMSG_OK(&msg.n, ret),
+ "nl_family response"))
goto fail;
nl = (struct nlattr *)GENLMSG_DATA(&msg);
diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h
index c9bfbe1bafc1..1cd783aec11a 100644
--- a/tools/testing/selftests/bpf/progs/bpf_misc.h
+++ b/tools/testing/selftests/bpf/progs/bpf_misc.h
@@ -140,7 +140,7 @@
#define __msg_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_msg_unpriv=" XSTR(__COUNTER__) "=" msg)))
#define __not_msg_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_not_msg_unpriv=" XSTR(__COUNTER__) "=" msg)))
#define __xlated_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_xlated_unpriv=" XSTR(__COUNTER__) "=" msg)))
-#define __jited_unpriv(msg) __attribute__((btf_decl_tag("comment:test_jited=" XSTR(__COUNTER__) "=" msg)))
+#define __jited_unpriv(msg) __attribute__((btf_decl_tag("comment:test_jited_unpriv=" XSTR(__COUNTER__) "=" msg)))
#define __failure_unpriv __attribute__((btf_decl_tag("comment:test_expect_failure_unpriv")))
#define __success_unpriv __attribute__((btf_decl_tag("comment:test_expect_success_unpriv")))
#define __log_level(lvl) __attribute__((btf_decl_tag("comment:test_log_level="#lvl)))
diff --git a/tools/testing/selftests/bpf/progs/bpf_smc.c b/tools/testing/selftests/bpf/progs/bpf_smc.c
index 70d8b08f5914..6263a45bf006 100644
--- a/tools/testing/selftests/bpf/progs/bpf_smc.c
+++ b/tools/testing/selftests/bpf/progs/bpf_smc.c
@@ -8,6 +8,10 @@
char _license[] SEC("license") = "GPL";
+#ifndef SMC_HS_CTRL_NAME_MAX
+#define SMC_HS_CTRL_NAME_MAX 16
+#endif
+
enum {
BPF_SMC_LISTEN = 10,
};
@@ -18,6 +22,20 @@ struct smc_sock___local {
bool use_fallback;
} __attribute__((preserve_access_index));
+struct smc_hs_ctrl___local {
+ char name[SMC_HS_CTRL_NAME_MAX];
+ int (*syn_option)(struct tcp_sock *);
+ int (*synack_option)(const struct tcp_sock *, struct inet_request_sock *);
+} __attribute__((preserve_access_index));
+
+struct netns_smc___local {
+ struct smc_hs_ctrl___local *hs_ctrl;
+} __attribute__((preserve_access_index));
+
+struct net___local {
+ struct netns_smc___local smc;
+} __attribute__((preserve_access_index));
+
int smc_cnt = 0;
int fallback_cnt = 0;
@@ -88,8 +106,14 @@ int BPF_PROG(smc_run, int family, int type, int protocol)
task = bpf_get_current_task_btf();
/* Prevent from affecting other tests */
- if (!task || !task->nsproxy->net_ns->smc.hs_ctrl)
+ if (!task) {
return protocol;
+ } else {
+ struct net___local *net = (struct net___local *)task->nsproxy->net_ns;
+
+ if (!bpf_core_field_exists(struct net___local, smc) || !net->smc.hs_ctrl)
+ return protocol;
+ }
return IPPROTO_SMC;
}
@@ -110,7 +134,7 @@ int BPF_PROG(bpf_smc_set_tcp_option, struct tcp_sock *tp)
}
SEC(".struct_ops")
-struct smc_hs_ctrl linkcheck = {
+struct smc_hs_ctrl___local linkcheck = {
.name = "linkcheck",
.syn_option = (void *)bpf_smc_set_tcp_option,
.synack_option = (void *)bpf_smc_set_tcp_option_cond,
diff --git a/tools/testing/selftests/bpf/progs/test_access_variable_array.c b/tools/testing/selftests/bpf/progs/test_access_variable_array.c
deleted file mode 100644
index 326b7d1f496a..000000000000
--- a/tools/testing/selftests/bpf/progs/test_access_variable_array.c
+++ /dev/null
@@ -1,19 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Copyright (c) 2023 Bytedance */
-
-#include "vmlinux.h"
-#include <bpf/bpf_helpers.h>
-#include <bpf/bpf_tracing.h>
-
-unsigned long span = 0;
-
-SEC("fentry/sched_balance_rq")
-int BPF_PROG(fentry_fentry, int this_cpu, struct rq *this_rq,
- struct sched_domain *sd)
-{
- span = sd->span[0];
-
- return 0;
-}
-
-char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/cgroup/test_memcontrol.c b/tools/testing/selftests/cgroup/test_memcontrol.c
index 2fb096a2a9f9..a25eb097b31c 100644
--- a/tools/testing/selftests/cgroup/test_memcontrol.c
+++ b/tools/testing/selftests/cgroup/test_memcontrol.c
@@ -1280,8 +1280,11 @@ static int tcp_server(const char *cgroup, void *arg)
saddr.sin6_port = htons(srv_args->port);
sk = socket(AF_INET6, SOCK_STREAM, 0);
- if (sk < 0)
+ if (sk < 0) {
+ /* Pass back errno to the ctl_fd */
+ write(ctl_fd, &errno, sizeof(errno));
return ret;
+ }
if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0)
goto cleanup;
@@ -1412,6 +1415,12 @@ static int test_memcg_sock(const char *root)
goto cleanup;
close(args.ctl[0]);
+ /* Skip if address family not supported by protocol */
+ if (err == EAFNOSUPPORT) {
+ ret = KSFT_SKIP;
+ goto cleanup;
+ }
+
if (!err)
break;
if (err != EADDRINUSE)
diff --git a/tools/testing/selftests/ftrace/ftracetest b/tools/testing/selftests/ftrace/ftracetest
index 3230bd54dba8..0a56bf209f6c 100755
--- a/tools/testing/selftests/ftrace/ftracetest
+++ b/tools/testing/selftests/ftrace/ftracetest
@@ -130,8 +130,7 @@ parse_opts() { # opts
shift 1
;;
--logdir|-l)
- LOG_DIR=$2
- LINK_PTR=
+ USER_LOG_DIR=$2
shift 2
;;
--rv)
@@ -199,6 +198,7 @@ fi
TOP_DIR=`absdir $0`
TEST_DIR=$TOP_DIR/test.d
TEST_CASES=`find_testcases $TEST_DIR`
+USER_LOG_DIR=
KEEP_LOG=0
KTAP=0
DEBUG=0
@@ -210,12 +210,18 @@ RV_TEST=0
# Parse command-line options
parse_opts $*
+[ $DEBUG -ne 0 ] && set -x
+
+# TOP_DIR can be changed for rv. Setting log directory.
LOG_TOP_DIR=$TOP_DIR/logs
LOG_DATE=`date +%Y%m%d-%H%M%S`
-LOG_DIR=$LOG_TOP_DIR/$LOG_DATE/
-LINK_PTR=$LOG_TOP_DIR/latest
-
-[ $DEBUG -ne 0 ] && set -x
+if [ -n "$USER_LOG_DIR" ]; then
+ LOG_DIR=$USER_LOG_DIR
+ LINK_PTR=
+else
+ LOG_DIR=$LOG_TOP_DIR/$LOG_DATE/
+ LINK_PTR=$LOG_TOP_DIR/latest
+fi
if [ $RV_TEST -ne 0 ]; then
TRACING_DIR=$TRACING_DIR/rv
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/trace_marker_raw.tc b/tools/testing/selftests/ftrace/test.d/00basic/trace_marker_raw.tc
index a2c42e13f614..8e905d4fe6dd 100644
--- a/tools/testing/selftests/ftrace/test.d/00basic/trace_marker_raw.tc
+++ b/tools/testing/selftests/ftrace/test.d/00basic/trace_marker_raw.tc
@@ -4,6 +4,8 @@
# requires: trace_marker_raw
# flags: instance
+check_awk_strtonum || exit_unresolved
+
is_little_endian() {
if lscpu | grep -q 'Little Endian'; then
echo 1;
diff --git a/tools/testing/selftests/ftrace/test.d/functions b/tools/testing/selftests/ftrace/test.d/functions
index e8e718139294..41325f387ee7 100644
--- a/tools/testing/selftests/ftrace/test.d/functions
+++ b/tools/testing/selftests/ftrace/test.d/functions
@@ -173,6 +173,10 @@ check_requires() { # Check required files and tracers
done
}
+check_awk_strtonum() { # strtonum is GNU awk extension
+ awk 'BEGIN{strtonum("0x1")}'
+}
+
LOCALHOST=127.0.0.1
yield() {
diff --git a/tools/testing/selftests/futex/functional/futex_requeue.c b/tools/testing/selftests/futex/functional/futex_requeue.c
index 35d4be23db5d..dcf0d5f2f312 100644
--- a/tools/testing/selftests/futex/functional/futex_requeue.c
+++ b/tools/testing/selftests/futex/functional/futex_requeue.c
@@ -34,34 +34,18 @@ TEST(requeue_single)
volatile futex_t _f1 = 0;
volatile futex_t f2 = 0;
pthread_t waiter[10];
- int res;
f1 = &_f1;
/*
* Requeue a waiter from f1 to f2, and wake f2.
*/
- if (pthread_create(&waiter[0], NULL, waiterfn, NULL))
- ksft_exit_fail_msg("pthread_create failed\n");
+ ASSERT_EQ(0, pthread_create(&waiter[0], NULL, waiterfn, NULL));
usleep(WAKE_WAIT_US);
- ksft_print_dbg_msg("Requeuing 1 futex from f1 to f2\n");
- res = futex_cmp_requeue(f1, 0, &f2, 0, 1, 0);
- if (res != 1)
- ksft_test_result_fail("futex_requeue simple returned: %d %s\n",
- res ? errno : res,
- res ? strerror(errno) : "");
-
- ksft_print_dbg_msg("Waking 1 futex at f2\n");
- res = futex_wake(&f2, 1, 0);
- if (res != 1) {
- ksft_test_result_fail("futex_requeue simple returned: %d %s\n",
- res ? errno : res,
- res ? strerror(errno) : "");
- } else {
- ksft_test_result_pass("futex_requeue simple succeeds\n");
- }
+ EXPECT_EQ(1, futex_cmp_requeue(f1, 0, &f2, 0, 1, 0));
+ EXPECT_EQ(1, futex_wake(&f2, 1, 0));
}
TEST(requeue_multiple)
@@ -69,7 +53,7 @@ TEST(requeue_multiple)
volatile futex_t _f1 = 0;
volatile futex_t f2 = 0;
pthread_t waiter[10];
- int res, i;
+ int i;
f1 = &_f1;
@@ -77,30 +61,13 @@ TEST(requeue_multiple)
* Create 10 waiters at f1. At futex_requeue, wake 3 and requeue 7.
* At futex_wake, wake INT_MAX (should be exactly 7).
*/
- for (i = 0; i < 10; i++) {
- if (pthread_create(&waiter[i], NULL, waiterfn, NULL))
- ksft_exit_fail_msg("pthread_create failed\n");
- }
+ for (i = 0; i < 10; i++)
+ ASSERT_EQ(0, pthread_create(&waiter[i], NULL, waiterfn, NULL));
usleep(WAKE_WAIT_US);
- ksft_print_dbg_msg("Waking 3 futexes at f1 and requeuing 7 futexes from f1 to f2\n");
- res = futex_cmp_requeue(f1, 0, &f2, 3, 7, 0);
- if (res != 10) {
- ksft_test_result_fail("futex_requeue many returned: %d %s\n",
- res ? errno : res,
- res ? strerror(errno) : "");
- }
-
- ksft_print_dbg_msg("Waking INT_MAX futexes at f2\n");
- res = futex_wake(&f2, INT_MAX, 0);
- if (res != 7) {
- ksft_test_result_fail("futex_requeue many returned: %d %s\n",
- res ? errno : res,
- res ? strerror(errno) : "");
- } else {
- ksft_test_result_pass("futex_requeue many succeeds\n");
- }
+ EXPECT_EQ(10, futex_cmp_requeue(f1, 0, &f2, 3, 7, 0));
+ EXPECT_EQ(7, futex_wake(&f2, INT_MAX, 0));
}
TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/mm/migration.c b/tools/testing/selftests/mm/migration.c
index ee24b88c2b24..60e78bbfc0e3 100644
--- a/tools/testing/selftests/mm/migration.c
+++ b/tools/testing/selftests/mm/migration.c
@@ -36,7 +36,8 @@ FIXTURE_SETUP(migration)
{
int n;
- ASSERT_EQ(numa_available(), 0);
+ if (numa_available() < 0)
+ SKIP(return, "NUMA not available");
self->nthreads = numa_num_task_cpus() - 1;
self->n1 = -1;
self->n2 = -1;
diff --git a/tools/testing/selftests/namespaces/listns_efault_test.c b/tools/testing/selftests/namespaces/listns_efault_test.c
index c7ed4023d7a8..b570746e917c 100644
--- a/tools/testing/selftests/namespaces/listns_efault_test.c
+++ b/tools/testing/selftests/namespaces/listns_efault_test.c
@@ -19,7 +19,6 @@
#include <sys/wait.h>
#include <unistd.h>
#include "../kselftest_harness.h"
-#include "../filesystems/utils.h"
#include "../pidfd/pidfd.h"
#include "wrappers.h"
diff --git a/tools/testing/selftests/net/netfilter/nft_tproxy_udp.sh b/tools/testing/selftests/net/netfilter/nft_tproxy_udp.sh
index d16de13fe5a7..1dc7b0450145 100755
--- a/tools/testing/selftests/net/netfilter/nft_tproxy_udp.sh
+++ b/tools/testing/selftests/net/netfilter/nft_tproxy_udp.sh
@@ -190,13 +190,13 @@ table inet filter {
}
EOF
- timeout "$timeout" ip netns exec "$nsrouter" socat -u "$socat_ipproto" udp-listen:12345,fork,ip-transparent,reuseport udp:"$ns1_ip_port",ip-transparent,reuseport,bind="$ns2_ip_port" 2>/dev/null &
+ timeout "$timeout" ip netns exec "$nsrouter" socat -u "$socat_ipproto" udp-listen:12345,fork,ip-transparent,reuseport,shut-none udp:"$ns1_ip_port",ip-transparent,reuseport,bind="$ns2_ip_port",shut-none 2>/dev/null &
local tproxy_pid=$!
- timeout "$timeout" ip netns exec "$ns2" socat "$socat_ipproto" udp-listen:8080,fork SYSTEM:"echo PONG_NS2" 2>/dev/null &
+ timeout "$timeout" ip netns exec "$ns2" socat "$socat_ipproto" udp-listen:8080,fork,shut-none SYSTEM:"echo PONG_NS2" 2>/dev/null &
local server2_pid=$!
- timeout "$timeout" ip netns exec "$ns3" socat "$socat_ipproto" udp-listen:8080,fork SYSTEM:"echo PONG_NS3" 2>/dev/null &
+ timeout "$timeout" ip netns exec "$ns3" socat "$socat_ipproto" udp-listen:8080,fork,shut-none SYSTEM:"echo PONG_NS3" 2>/dev/null &
local server3_pid=$!
busywait "$BUSYWAIT_TIMEOUT" listener_ready "$nsrouter" 12345 "-u"
@@ -205,7 +205,7 @@ EOF
local result
# request from ns1 to ns2 (forwarded traffic)
- result=$(echo I_M_PROXIED | ip netns exec "$ns1" socat -t 2 -T 2 STDIO udp:"$ns2_ip_port",sourceport=18888)
+ result=$(echo I_M_PROXIED | ip netns exec "$ns1" socat -t 2 -T 2 STDIO udp:"$ns2_ip_port",sourceport=18888,shut-none)
if [ "$result" == "$expect_ns1_ns2" ] ;then
echo "PASS: tproxy test $testname: ns1 got reply \"$result\" connecting to ns2"
else
@@ -214,7 +214,7 @@ EOF
fi
# request from ns1 to ns3 (forwarded traffic)
- result=$(echo I_M_PROXIED | ip netns exec "$ns1" socat -t 2 -T 2 STDIO udp:"$ns3_ip_port")
+ result=$(echo I_M_PROXIED | ip netns exec "$ns1" socat -t 2 -T 2 STDIO udp:"$ns3_ip_port",shut-none)
if [ "$result" = "$expect_ns1_ns3" ] ;then
echo "PASS: tproxy test $testname: ns1 got reply \"$result\" connecting to ns3"
else
@@ -223,7 +223,7 @@ EOF
fi
# request from nsrouter to ns2 (localy originated traffic)
- result=$(echo I_M_PROXIED | ip netns exec "$nsrouter" socat -t 2 -T 2 STDIO udp:"$ns2_ip_port")
+ result=$(echo I_M_PROXIED | ip netns exec "$nsrouter" socat -t 2 -T 2 STDIO udp:"$ns2_ip_port",shut-none)
if [ "$result" == "$expect_nsrouter_ns2" ] ;then
echo "PASS: tproxy test $testname: nsrouter got reply \"$result\" connecting to ns2"
else
@@ -232,7 +232,7 @@ EOF
fi
# request from nsrouter to ns3 (localy originated traffic)
- result=$(echo I_M_PROXIED | ip netns exec "$nsrouter" socat -t 2 -T 2 STDIO udp:"$ns3_ip_port")
+ result=$(echo I_M_PROXIED | ip netns exec "$nsrouter" socat -t 2 -T 2 STDIO udp:"$ns3_ip_port",shut-none)
if [ "$result" = "$expect_nsrouter_ns3" ] ;then
echo "PASS: tproxy test $testname: nsrouter got reply \"$result\" connecting to ns3"
else
diff --git a/tools/testing/selftests/net/packetdrill/tcp_ts_recent_invalid_ack.pkt b/tools/testing/selftests/net/packetdrill/tcp_ts_recent_invalid_ack.pkt
index 174ce9a1bfc0..ee6baf7c36cf 100644
--- a/tools/testing/selftests/net/packetdrill/tcp_ts_recent_invalid_ack.pkt
+++ b/tools/testing/selftests/net/packetdrill/tcp_ts_recent_invalid_ack.pkt
@@ -19,7 +19,9 @@
// bad packet with high tsval (its ACK sequence is above our sndnxt)
+0 < F. 1:1(0) ack 9999 win 20000 <nop,nop,TS val 200000 ecr 100>
-
+// Challenge ACK for SEG.ACK > SND.NXT (RFC 5961 5.2 / RFC 793 3.9).
+// ecr=200 (not 200000) proves ts_recent was not updated from the bad packet.
+ +0 > . 1:1(0) ack 1 <nop,nop,TS val 200 ecr 200>
+0 < . 1:1001(1000) ack 1 win 20000 <nop,nop,TS val 201 ecr 100>
+0 > . 1:1(0) ack 1001 <nop,nop,TS val 200 ecr 201>
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index 1b9d3b2e2491..801b2ad18853 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -74,6 +74,28 @@ static const int is_nolibc =
#endif
;
+static const int is_glibc =
+#ifdef __GLIBC__
+ 1
+#else
+ 0
+#endif
+;
+
+#if !defined(NOLIBC)
+/* Some disabled tests may not compile. */
+
+/* strlcat() and strlcpy() may not be in the system headers. */
+#undef strlcat
+#undef strlcpy
+#define strlcat(d, s, l) 0
+#define strlcpy(d, s, l) 0
+
+/* readdir_r() is likely to be marked deprecated */
+#undef readdir_r
+#define readdir_r(dir, dirent, result) ((errno = EINVAL), -1)
+#endif
+
/* definition of a series of tests */
struct test {
const char *name; /* test name */
@@ -866,7 +888,7 @@ int test_file_stream(void)
errno = 0;
r = fwrite("foo", 1, 3, f);
- if (r != 0 || errno != EBADF) {
+ if (r != 0 || ((is_nolibc || is_glibc) && errno != EBADF)) {
fclose(f);
return -1;
}
@@ -1408,7 +1430,7 @@ int run_syscall(int min, int max)
CASE_TEST(fork); EXPECT_SYSZR(1, test_fork(FORK_STANDARD)); break;
CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break;
CASE_TEST(getdents64_null); EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break;
- CASE_TEST(directories); EXPECT_SYSZR(proc, test_dirent()); break;
+ CASE_TEST(directories); EXPECT_SYSZR(is_nolibc && proc, test_dirent()); break;
CASE_TEST(getrandom); EXPECT_SYSZR(1, test_getrandom()); break;
CASE_TEST(gettimeofday_tv); EXPECT_SYSZR(1, gettimeofday(&tv, NULL)); break;
CASE_TEST(gettimeofday_tv_tz);EXPECT_SYSZR(1, gettimeofday(&tv, &tz)); break;
diff --git a/tools/testing/selftests/powerpc/vphn/Makefile b/tools/testing/selftests/powerpc/vphn/Makefile
index 61d519a076c6..778fc396340d 100644
--- a/tools/testing/selftests/powerpc/vphn/Makefile
+++ b/tools/testing/selftests/powerpc/vphn/Makefile
@@ -5,7 +5,7 @@ top_srcdir = ../../../../..
include ../../lib.mk
include ../flags.mk
-CFLAGS += -m64 -I$(CURDIR)
+CFLAGS += -m64 -I$(CURDIR) -fno-strict-aliasing
$(TEST_GEN_PROGS): ../harness.c
diff --git a/tools/testing/selftests/sched_ext/exit.c b/tools/testing/selftests/sched_ext/exit.c
index ee25824b1cbe..b987611789d1 100644
--- a/tools/testing/selftests/sched_ext/exit.c
+++ b/tools/testing/selftests/sched_ext/exit.c
@@ -33,7 +33,7 @@ static enum scx_test_status run(void *ctx)
skel = exit__open();
SCX_ENUM_INIT(skel);
skel->rodata->exit_point = tc;
- exit__load(skel);
+ SCX_FAIL_IF(exit__load(skel), "Failed to load skel");
link = bpf_map__attach_struct_ops(skel->maps.exit_ops);
if (!link) {
SCX_ERR("Failed to attach scheduler");
diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile
index 8e90e409e91d..0684932d91bf 100644
--- a/tools/testing/selftests/vfio/Makefile
+++ b/tools/testing/selftests/vfio/Makefile
@@ -1,6 +1,6 @@
ARCH ?= $(shell uname -m)
-ifeq (,$(filter $(ARCH),arm64 x86_64))
+ifeq (,$(filter $(ARCH),aarch64 arm64 x86_64))
# Do nothing on unsupported architectures
include ../lib.mk
else
diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_mmio_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_mmio_test.c
index 957a89ce7b3a..d7f25ef77671 100644
--- a/tools/testing/selftests/vfio/vfio_dma_mapping_mmio_test.c
+++ b/tools/testing/selftests/vfio/vfio_dma_mapping_mmio_test.c
@@ -100,7 +100,6 @@ static void do_mmio_map_test(struct iommu *iommu,
iommu_unmap(iommu, ®ion);
} else {
VFIO_ASSERT_NE(__iommu_map(iommu, ®ion), 0);
- VFIO_ASSERT_NE(__iommu_unmap(iommu, ®ion, NULL), 0);
}
}
diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c
index ceff76a62a30..839c78c065e1 100644
--- a/tools/tracing/rtla/src/common.c
+++ b/tools/tracing/rtla/src/common.c
@@ -39,6 +39,48 @@ static void set_signals(struct common_params *params)
}
}
+/*
+ * unset_signals - unsets the signals to stop the tool
+ */
+static void unset_signals(struct common_params *params)
+{
+ signal(SIGINT, SIG_DFL);
+ if (params->duration) {
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+ }
+}
+
+/*
+ * getopt_auto - auto-generates optstring from long_options
+ */
+int getopt_auto(int argc, char **argv, const struct option *long_opts)
+{
+ char opts[256];
+ int n = 0;
+
+ for (int i = 0; long_opts[i].name; i++) {
+ if (long_opts[i].val < 32 || long_opts[i].val > 127)
+ continue;
+
+ if (n + 4 >= sizeof(opts))
+ fatal("optstring buffer overflow");
+
+ opts[n++] = long_opts[i].val;
+
+ if (long_opts[i].has_arg == required_argument)
+ opts[n++] = ':';
+ else if (long_opts[i].has_arg == optional_argument) {
+ opts[n++] = ':';
+ opts[n++] = ':';
+ }
+ }
+
+ opts[n] = '\0';
+
+ return getopt_long(argc, argv, opts, long_opts, NULL);
+}
+
/*
* common_parse_options - parse common command line options
*
@@ -69,7 +111,7 @@ int common_parse_options(int argc, char **argv, struct common_params *common)
};
opterr = 0;
- c = getopt_long(argc, argv, "c:C::Dd:e:H:P:", long_options, NULL);
+ c = getopt_auto(argc, argv, long_options);
opterr = 1;
switch (c) {
@@ -284,7 +326,7 @@ int run_tool(struct tool_ops *ops, int argc, char *argv[])
retval = ops->main(tool);
if (retval)
- goto out_trace;
+ goto out_signals;
if (params->user_workload && !params->user.stopped_running) {
params->user.should_run = 0;
@@ -306,6 +348,8 @@ int run_tool(struct tool_ops *ops, int argc, char *argv[])
if (ops->analyze)
ops->analyze(tool, stopped);
+out_signals:
+ unset_signals(params);
out_trace:
trace_events_destroy(&tool->record->trace, params->events);
params->events = NULL;
diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h
index 7602c5593ef5..d4b3715700be 100644
--- a/tools/tracing/rtla/src/common.h
+++ b/tools/tracing/rtla/src/common.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
#pragma once
+#include <getopt.h>
#include "actions.h"
#include "timerlat_u.h"
#include "trace.h"
@@ -156,6 +157,7 @@ int osnoise_set_stop_us(struct osnoise_context *context, long long stop_us);
int osnoise_set_stop_total_us(struct osnoise_context *context,
long long stop_total_us);
+int getopt_auto(int argc, char **argv, const struct option *long_opts);
int common_parse_options(int argc, char **argv, struct common_params *common);
int common_apply_config(struct osnoise_tool *tool, struct common_params *params);
int top_main_loop(struct osnoise_tool *tool);
diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c
index 9d70ea34807f..5c863e7aad28 100644
--- a/tools/tracing/rtla/src/osnoise_hist.c
+++ b/tools/tracing/rtla/src/osnoise_hist.c
@@ -506,8 +506,7 @@ static struct common_params
if (common_parse_options(argc, argv, ¶ms->common))
continue;
- c = getopt_long(argc, argv, "a:b:E:hp:r:s:S:t::T:01234:5:6:7:",
- long_options, NULL);
+ c = getopt_auto(argc, argv, long_options);
/* detect the end of the options. */
if (c == -1)
diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c
index d54d47947fb4..b7aed40fd216 100644
--- a/tools/tracing/rtla/src/osnoise_top.c
+++ b/tools/tracing/rtla/src/osnoise_top.c
@@ -358,8 +358,7 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv)
if (common_parse_options(argc, argv, ¶ms->common))
continue;
- c = getopt_long(argc, argv, "a:hp:qr:s:S:t::T:0:1:2:3:",
- long_options, NULL);
+ c = getopt_auto(argc, argv, long_options);
/* Detect the end of the options. */
if (c == -1)
diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c
index 4e8c38a61197..096de8ba3efb 100644
--- a/tools/tracing/rtla/src/timerlat_hist.c
+++ b/tools/tracing/rtla/src/timerlat_hist.c
@@ -825,8 +825,7 @@ static struct common_params
if (common_parse_options(argc, argv, ¶ms->common))
continue;
- c = getopt_long(argc, argv, "a:b:E:hi:knp:s:t::T:uU0123456:7:8:9\1\2:\3:",
- long_options, NULL);
+ c = getopt_auto(argc, argv, long_options);
/* detect the end of the options. */
if (c == -1)
diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c
index 284b74773c2b..27c14aa71a8b 100644
--- a/tools/tracing/rtla/src/timerlat_top.c
+++ b/tools/tracing/rtla/src/timerlat_top.c
@@ -588,8 +588,7 @@ static struct common_params
if (common_parse_options(argc, argv, ¶ms->common))
continue;
- c = getopt_long(argc, argv, "a:hi:knp:qs:t::T:uU0:1:2:345:6:7:",
- long_options, NULL);
+ c = getopt_auto(argc, argv, long_options);
/* detect the end of the options. */
if (c == -1)
diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c
index 0da3b2470c31..8d5e3b9724b9 100644
--- a/tools/tracing/rtla/src/utils.c
+++ b/tools/tracing/rtla/src/utils.c
@@ -361,22 +361,23 @@ int set_comm_sched_attr(const char *comm_prefix, struct sched_attr *attr)
if (strtoi(proc_entry->d_name, &pid)) {
err_msg("'%s' is not a valid pid", proc_entry->d_name);
- goto out_err;
+ retval = 1;
+ goto out;
}
/* procfs_is_workload_pid confirmed it is a pid */
retval = __set_sched_attr(pid, attr);
if (retval) {
err_msg("Error setting sched attributes for pid:%s\n", proc_entry->d_name);
- goto out_err;
+ goto out;
}
debug_msg("Set sched attributes for pid:%s\n", proc_entry->d_name);
}
- return 0;
-out_err:
+ retval = 0;
+out:
closedir(procfs);
- return 1;
+ return retval;
}
#define INVALID_VAL (~0L)
diff --git a/virt/kvm/dirty_ring.c b/virt/kvm/dirty_ring.c
index 02bc6b00d76c..572b854edf74 100644
--- a/virt/kvm/dirty_ring.c
+++ b/virt/kvm/dirty_ring.c
@@ -63,7 +63,8 @@ static void kvm_reset_dirty_gfn(struct kvm *kvm, u32 slot, u64 offset, u64 mask)
memslot = id_to_memslot(__kvm_memslots(kvm, as_id), id);
- if (!memslot || (offset + __fls(mask)) >= memslot->npages)
+ if (!memslot || offset >= memslot->npages ||
+ offset + __fls(mask) >= memslot->npages)
return;
KVM_MMU_LOCK(kvm);
^ permalink raw reply related [flat|nested] 2+ messages in thread